diff --git a/src/doc/reference.md b/src/doc/reference.md index 0262ff5a71a..a20d2571152 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2390,6 +2390,8 @@ The currently implemented features of the reference compiler are: * - `stmt_expr_attributes` - Allows attributes on expressions and non-item statements. +* - `deprecated` - Allows using the `#[deprecated]` attribute. + If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled the new feature (because the directive is no longer necessary). However, if a diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 22a4ddd2f68..2c3b89bf2fb 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -135,6 +135,7 @@ pub enum FoundAst<'ast> { pub trait CrateStore<'tcx> : Any { // item info fn stability(&self, def: DefId) -> Option; + fn deprecation(&self, def: DefId) -> Option; fn closure_kind(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureKind; fn closure_ty(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) @@ -292,6 +293,7 @@ pub struct DummyCrateStore; impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // item info fn stability(&self, def: DefId) -> Option { unimplemented!() } + fn deprecation(&self, def: DefId) -> Option { unimplemented!() } fn closure_kind(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureKind { unimplemented!() } fn closure_ty(&self, tcx: &ty::ctxt<'tcx>, def_id: DefId) diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 0d92c3da83c..f7e2135d5a4 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -25,7 +25,7 @@ use syntax::codemap::{Span, DUMMY_SP}; use syntax::ast; use syntax::ast::{NodeId, Attribute}; use syntax::feature_gate::{GateIssue, emit_feature_err}; -use syntax::attr::{self, Stability, AttrMetaMethods}; +use syntax::attr::{self, Stability, Deprecation, AttrMetaMethods}; use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap}; use rustc_front::hir; @@ -61,7 +61,8 @@ enum AnnotationKind { pub struct Index<'tcx> { /// This is mostly a cache, except the stabilities of local items /// are filled by the annotator. - map: DefIdMap>, + stab_map: DefIdMap>, + depr_map: DefIdMap>, /// Maps for each crate whether it is part of the staged API. staged_api: FnvHashMap @@ -71,7 +72,8 @@ pub struct Index<'tcx> { struct Annotator<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, index: &'a mut Index<'tcx>, - parent: Option<&'tcx Stability>, + parent_stab: Option<&'tcx Stability>, + parent_depr: Option, access_levels: &'a AccessLevels, in_trait_impl: bool, in_enum: bool, @@ -86,22 +88,26 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { { if self.index.staged_api[&LOCAL_CRATE] && self.tcx.sess.features.borrow().staged_api { debug!("annotate(id = {:?}, attrs = {:?})", id, attrs); + if let Some(..) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) { + self.tcx.sess.span_err(item_sp, "`#[deprecated]` cannot be used in staged api, \ + use `#[rustc_deprecated]` instead"); + } if let Some(mut stab) = attr::find_stability(self.tcx.sess.diagnostic(), attrs, item_sp) { // Error if prohibited, or can't inherit anything from a container if kind == AnnotationKind::Prohibited || (kind == AnnotationKind::Container && stab.level.is_stable() && - stab.depr.is_none()) { + stab.rustc_depr.is_none()) { self.tcx.sess.span_err(item_sp, "This stability annotation is useless"); } debug!("annotate: found {:?}", stab); // If parent is deprecated and we're not, inherit this by merging // deprecated_since and its reason. - if let Some(parent_stab) = self.parent { - if parent_stab.depr.is_some() && stab.depr.is_none() { - stab.depr = parent_stab.depr.clone() + if let Some(parent_stab) = self.parent_stab { + if parent_stab.rustc_depr.is_some() && stab.rustc_depr.is_none() { + stab.rustc_depr = parent_stab.rustc_depr.clone() } } @@ -109,8 +115,8 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { // Check if deprecated_since < stable_since. If it is, // this is *almost surely* an accident. - if let (&Some(attr::Deprecation {since: ref dep_since, ..}), - &attr::Stable {since: ref stab_since}) = (&stab.depr, &stab.level) { + if let (&Some(attr::RustcDeprecation {since: ref dep_since, ..}), + &attr::Stable {since: ref stab_since}) = (&stab.rustc_depr, &stab.level) { // Explicit version of iter::order::lt to handle parse errors properly for (dep_v, stab_v) in dep_since.split(".").zip(stab_since.split(".")) { if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::(), stab_v.parse()) { @@ -134,20 +140,20 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { } let def_id = self.tcx.map.local_def_id(id); - self.index.map.insert(def_id, Some(stab)); + self.index.stab_map.insert(def_id, Some(stab)); - let parent = replace(&mut self.parent, Some(stab)); + let orig_parent_stab = replace(&mut self.parent_stab, Some(stab)); visit_children(self); - self.parent = parent; + self.parent_stab = orig_parent_stab; } else { - debug!("annotate: not found, parent = {:?}", self.parent); + debug!("annotate: not found, parent = {:?}", self.parent_stab); let mut is_error = kind == AnnotationKind::Required && self.access_levels.is_reachable(id) && !self.tcx.sess.opts.test; - if let Some(stab) = self.parent { + if let Some(stab) = self.parent_stab { if stab.level.is_unstable() { let def_id = self.tcx.map.local_def_id(id); - self.index.map.insert(def_id, Some(stab)); + self.index.stab_map.insert(def_id, Some(stab)); is_error = false; } } @@ -165,9 +171,35 @@ 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"); + } } } - visit_children(self); + + if let Some(depr) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) { + if kind == AnnotationKind::Prohibited { + self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless"); + } + + // `Deprecation` is just two pointers, no need to intern it + let def_id = self.tcx.map.local_def_id(id); + self.index.depr_map.insert(def_id, Some(depr.clone())); + + let orig_parent_depr = replace(&mut self.parent_depr, Some(depr)); + visit_children(self); + self.parent_depr = orig_parent_depr; + } else if let Some(depr) = self.parent_depr.clone() { + let def_id = self.tcx.map.local_def_id(id); + self.index.depr_map.insert(def_id, Some(depr)); + visit_children(self); + } else { + visit_children(self); + } } } } @@ -269,7 +301,8 @@ impl<'tcx> Index<'tcx> { let mut annotator = Annotator { tcx: tcx, index: self, - parent: None, + parent_stab: None, + parent_depr: None, access_levels: access_levels, in_trait_impl: false, in_enum: false, @@ -291,7 +324,8 @@ impl<'tcx> Index<'tcx> { staged_api.insert(LOCAL_CRATE, is_staged_api); Index { staged_api: staged_api, - map: DefIdMap(), + stab_map: DefIdMap(), + depr_map: DefIdMap(), } } } @@ -327,7 +361,11 @@ struct Checker<'a, 'tcx: 'a> { } impl<'a, 'tcx> Checker<'a, 'tcx> { - fn check(&mut self, id: DefId, span: Span, stab: &Option<&Stability>) { + fn check(&mut self, id: DefId, span: Span, + stab: &Option<&Stability>, _depr: &Option) { + if !is_staged_api(self.tcx, id) { + return; + } // Only the cross-crate scenario matters when checking unstable APIs let cross_crate = !id.is_local(); if !cross_crate { @@ -395,31 +433,31 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { if item.span == DUMMY_SP && item.name.as_str() == "__test" { return } check_item(self.tcx, item, true, - &mut |id, sp, stab| self.check(id, sp, stab)); + &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_item(self, item); } fn visit_expr(&mut self, ex: &hir::Expr) { check_expr(self.tcx, ex, - &mut |id, sp, stab| self.check(id, sp, stab)); + &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_expr(self, ex); } fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) { check_path(self.tcx, path, id, - &mut |id, sp, stab| self.check(id, sp, stab)); + &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_path(self, path) } fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) { check_path_list_item(self.tcx, item, - &mut |id, sp, stab| self.check(id, sp, stab)); + &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_path_list_item(self, prefix, item) } fn visit_pat(&mut self, pat: &hir::Pat) { check_pat(self.tcx, pat, - &mut |id, sp, stab| self.check(id, sp, stab)); + &mut |id, sp, stab, depr| self.check(id, sp, stab, depr)); intravisit::walk_pat(self, pat) } @@ -441,7 +479,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> { /// Helper for discovering nodes to check for stability pub fn check_item(tcx: &ty::ctxt, item: &hir::Item, warn_about_defns: bool, - cb: &mut FnMut(DefId, Span, &Option<&Stability>)) { + cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option)) { match item.node { hir::ItemExternCrate(_) => { // compiler-generated `extern crate` items have a dummy span. @@ -478,7 +516,7 @@ pub fn check_item(tcx: &ty::ctxt, item: &hir::Item, warn_about_defns: bool, /// Helper for discovering nodes to check for stability pub fn check_expr(tcx: &ty::ctxt, e: &hir::Expr, - cb: &mut FnMut(DefId, Span, &Option<&Stability>)) { + cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option)) { let span; let id = match e.node { hir::ExprMethodCall(i, _, _) => { @@ -539,7 +577,7 @@ pub fn check_expr(tcx: &ty::ctxt, e: &hir::Expr, } pub fn check_path(tcx: &ty::ctxt, path: &hir::Path, id: ast::NodeId, - cb: &mut FnMut(DefId, Span, &Option<&Stability>)) { + cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option)) { match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) { Some(def::DefPrimTy(..)) => {} Some(def::DefSelfTy(..)) => {} @@ -551,7 +589,7 @@ pub fn check_path(tcx: &ty::ctxt, path: &hir::Path, id: ast::NodeId, } pub fn check_path_list_item(tcx: &ty::ctxt, item: &hir::PathListItem, - cb: &mut FnMut(DefId, Span, &Option<&Stability>)) { + cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option)) { match tcx.def_map.borrow().get(&item.node.id()).map(|d| d.full_def()) { Some(def::DefPrimTy(..)) => {} Some(def) => { @@ -562,7 +600,7 @@ pub fn check_path_list_item(tcx: &ty::ctxt, item: &hir::PathListItem, } pub fn check_pat(tcx: &ty::ctxt, pat: &hir::Pat, - cb: &mut FnMut(DefId, Span, &Option<&Stability>)) { + cb: &mut FnMut(DefId, Span, &Option<&Stability>, &Option)) { debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } @@ -591,21 +629,21 @@ pub fn check_pat(tcx: &ty::ctxt, pat: &hir::Pat, } fn maybe_do_stability_check(tcx: &ty::ctxt, id: DefId, span: Span, - cb: &mut FnMut(DefId, Span, &Option<&Stability>)) { - if !is_staged_api(tcx, id) { - debug!("maybe_do_stability_check: \ - skipping id={:?} since it is not staged_api", id); - return; - } + cb: &mut FnMut(DefId, Span, + &Option<&Stability>, &Option)) { if is_internal(tcx, span) { debug!("maybe_do_stability_check: \ skipping span={:?} since it is internal", span); return; } - let ref stability = lookup(tcx, id); + let (stability, deprecation) = if is_staged_api(tcx, id) { + (lookup_stability(tcx, id), None) + } else { + (None, lookup_deprecation(tcx, id)) + }; debug!("maybe_do_stability_check: \ inspecting id={:?} span={:?} of stability={:?}", id, span, stability); - cb(id, span, stability); + cb(id, span, &stability, &deprecation); } fn is_internal(tcx: &ty::ctxt, span: Span) -> bool { @@ -627,24 +665,34 @@ fn is_staged_api(tcx: &ty::ctxt, id: DefId) -> bool { /// Lookup the stability for a node, loading external crate /// metadata as necessary. -pub fn lookup<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> { - if let Some(st) = tcx.stability.borrow().map.get(&id) { +pub fn lookup_stability<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> { + if let Some(st) = tcx.stability.borrow().stab_map.get(&id) { return *st; } - let st = lookup_uncached(tcx, id); - tcx.stability.borrow_mut().map.insert(id, st); + let st = lookup_stability_uncached(tcx, id); + tcx.stability.borrow_mut().stab_map.insert(id, st); st } -fn lookup_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stability> { +pub fn lookup_deprecation<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option { + if let Some(depr) = tcx.stability.borrow().depr_map.get(&id) { + return depr.clone(); + } + + let depr = lookup_deprecation_uncached(tcx, id); + tcx.stability.borrow_mut().depr_map.insert(id, depr.clone()); + depr +} + +fn lookup_stability_uncached<'tcx>(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(tcx, trait_method_id) + return lookup_stability(tcx, trait_method_id) } _ => {} } @@ -663,7 +711,40 @@ fn lookup_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<&'tcx Stabil // unmarked impls for it. See FIXME above for more details. debug!("lookup: trait_id={:?}", trait_id); - return lookup(tcx, 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() { + 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 diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 90d9bcfffee..249504cbd8d 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -575,74 +575,71 @@ impl LateLintPass for MissingDebugImplementations { declare_lint! { DEPRECATED, Warn, - "detects use of #[rustc_deprecated] items" + "detects use of `#[deprecated]` or `#[rustc_deprecated]` items" } -/// Checks for use of items with `#[rustc_deprecated]` attributes +/// Checks for use of items with `#[deprecated]` or `#[rustc_deprecated]` attributes #[derive(Copy, Clone)] -pub struct Stability; +pub struct Deprecated; -impl Stability { - fn lint(&self, cx: &LateContext, _id: DefId, - span: Span, stability: &Option<&attr::Stability>) { +impl Deprecated { + fn lint(&self, cx: &LateContext, _id: DefId, span: Span, + stability: &Option<&attr::Stability>, deprecation: &Option) { // Deprecated attributes apply in-crate and cross-crate. - let (lint, label) = match *stability { - Some(&attr::Stability { depr: Some(_), .. }) => - (DEPRECATED, "deprecated"), - _ => return - }; + if let Some(&attr::Stability{rustc_depr: Some(attr::RustcDeprecation{ref reason, ..}), ..}) + = *stability { + output(cx, DEPRECATED, span, Some(&reason)) + } else if let Some(attr::Deprecation{ref note, ..}) = *deprecation { + output(cx, DEPRECATED, span, note.as_ref().map(|x| &**x)) + } - output(cx, span, stability, lint, label); - - fn output(cx: &LateContext, span: Span, stability: &Option<&attr::Stability>, - lint: &'static Lint, label: &'static str) { - let msg = match *stability { - Some(&attr::Stability {depr: Some(attr::Deprecation {ref reason, ..}), ..}) => { - format!("use of {} item: {}", label, reason) - } - _ => format!("use of {} item", label) + fn output(cx: &LateContext, lint: &'static Lint, span: Span, note: Option<&str>) { + let msg = if let Some(note) = note { + format!("use of deprecated item: {}", note) + } else { + format!("use of deprecated item") }; - cx.span_lint(lint, span, &msg[..]); + cx.span_lint(lint, span, &msg); } } } -impl LintPass for Stability { +impl LintPass for Deprecated { fn get_lints(&self) -> LintArray { lint_array!(DEPRECATED) } } -impl LateLintPass for Stability { +impl LateLintPass for Deprecated { fn check_item(&mut self, cx: &LateContext, item: &hir::Item) { stability::check_item(cx.tcx, item, false, - &mut |id, sp, stab| - self.lint(cx, id, sp, &stab)); + &mut |id, sp, stab, depr| + self.lint(cx, id, sp, &stab, &depr)); } fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) { stability::check_expr(cx.tcx, e, - &mut |id, sp, stab| - self.lint(cx, id, sp, &stab)); + &mut |id, sp, stab, depr| + self.lint(cx, id, sp, &stab, &depr)); } fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) { stability::check_path(cx.tcx, path, id, - &mut |id, sp, stab| - self.lint(cx, id, sp, &stab)); + &mut |id, sp, stab, depr| + self.lint(cx, id, sp, &stab, &depr)); } fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) { stability::check_path_list_item(cx.tcx, item, - &mut |id, sp, stab| - self.lint(cx, id, sp, &stab)); + &mut |id, sp, stab, depr| + self.lint(cx, id, sp, &stab, &depr)); } fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) { stability::check_pat(cx.tcx, pat, - &mut |id, sp, stab| - self.lint(cx, id, sp, &stab)); + &mut |id, sp, stab, depr| + self.lint(cx, id, sp, &stab, &depr)); } } diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 1d7431404f5..69fd569c8d4 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -124,7 +124,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UnusedAllocation, MissingCopyImplementations, UnstableFeatures, - Stability, + Deprecated, UnconditionalRecursion, InvalidNoMangleItems, PluginAsLibrary, diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 5186c969133..479ab759278 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -237,6 +237,8 @@ pub const tag_impl_coerce_unsized_kind: usize = 0xa5; pub const tag_items_data_item_constness: usize = 0xa6; +pub const tag_items_data_item_deprecation: usize = 0xa7; + pub const tag_rustc_version: usize = 0x10f; pub fn rustc_version() -> String { format!( diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index ad00ef29e5f..ecbc8402330 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -42,6 +42,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_stability(&*cdata, def.index) } + fn deprecation(&self, def: DefId) -> Option + { + let cdata = self.get_crate_data(def.krate); + decoder::get_deprecation(&*cdata, def.index) + } + fn closure_kind(&self, _tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureKind { assert!(!def_id.is_local()); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d1917b29b9f..357158c24ba 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -526,6 +526,14 @@ pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option { }) } +pub fn get_deprecation(cdata: Cmd, id: DefIndex) -> Option { + let item = cdata.lookup_item(id); + reader::maybe_get_doc(item, tag_items_data_item_deprecation).map(|doc| { + let mut decoder = reader::Decoder::new(doc); + Decodable::decode(&mut decoder).unwrap() + }) +} + pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec { let item = cdata.lookup_item(id); match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a627eeb6880..888776eaa56 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -342,8 +342,10 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_attributes(rbml_w, &attrs); encode_repr_attrs(rbml_w, ecx, &attrs); - let stab = stability::lookup(ecx.tcx, vid); + let stab = stability::lookup_stability(ecx.tcx, vid); + let depr = stability::lookup_deprecation(ecx.tcx, vid); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); encode_struct_fields(rbml_w, variant); @@ -450,8 +452,10 @@ fn encode_info_for_mod(ecx: &EncodeContext, encode_path(rbml_w, path.clone()); encode_visibility(rbml_w, vis); - let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(id)); + let stab = stability::lookup_stability(ecx.tcx, ecx.tcx.map.local_def_id(id)); + let depr = stability::lookup_deprecation(ecx.tcx, ecx.tcx.map.local_def_id(id)); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); // Encode the reexports of this module, if this module is public. if vis == hir::Public { @@ -538,8 +542,10 @@ fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_bounds_and_type_for_item(rbml_w, ecx, index, id); encode_def_id_and_key(ecx, rbml_w, field.did); - let stab = stability::lookup(ecx.tcx, field.did); + let stab = stability::lookup_stability(ecx.tcx, field.did); + let depr = stability::lookup_deprecation(ecx.tcx, field.did); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); rbml_w.end_tag(); } @@ -565,8 +571,10 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_symbol(ecx, rbml_w, ctor_id); } - let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(ctor_id)); + let stab = stability::lookup_stability(ecx.tcx, ecx.tcx.map.local_def_id(ctor_id)); + let depr= stability::lookup_deprecation(ecx.tcx, ecx.tcx.map.local_def_id(ctor_id)); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); // indicate that this is a tuple struct ctor, because downstream users will normally want // the tuple struct definition, but without this there is no way for them to tell that @@ -700,8 +708,10 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_bounds_and_type_for_item(rbml_w, ecx, index, ecx.local_id(associated_const.def_id)); - let stab = stability::lookup(ecx.tcx, associated_const.def_id); + let stab = stability::lookup_stability(ecx.tcx, associated_const.def_id); + let depr = stability::lookup_deprecation(ecx.tcx, associated_const.def_id); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); let elem = ast_map::PathName(associated_const.name); encode_path(rbml_w, impl_path.chain(Some(elem))); @@ -735,8 +745,10 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); encode_item_sort(rbml_w, 'r'); - let stab = stability::lookup(ecx.tcx, m.def_id); + let stab = stability::lookup_stability(ecx.tcx, m.def_id); + let depr = stability::lookup_deprecation(ecx.tcx, m.def_id); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); let m_node_id = ecx.local_id(m.def_id); encode_bounds_and_type_for_item(rbml_w, ecx, index, m_node_id); @@ -789,8 +801,10 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id)); encode_item_sort(rbml_w, 't'); - let stab = stability::lookup(ecx.tcx, associated_type.def_id); + let stab = stability::lookup_stability(ecx.tcx, associated_type.def_id); + let depr = stability::lookup_deprecation(ecx.tcx, associated_type.def_id); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); let elem = ast_map::PathName(associated_type.name); encode_path(rbml_w, impl_path.chain(Some(elem))); @@ -891,6 +905,14 @@ fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) { }); } +fn encode_deprecation(rbml_w: &mut Encoder, depr_opt: Option) { + depr_opt.map(|depr| { + rbml_w.start_tag(tag_items_data_item_deprecation); + depr.encode(rbml_w).unwrap(); + rbml_w.end_tag(); + }); +} + fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, xrefs: FnvHashMap, u32>) @@ -931,7 +953,8 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, tcx.sess.codemap().span_to_string(item.span)); let def_id = ecx.tcx.map.local_def_id(item.id); - let stab = stability::lookup(tcx, ecx.tcx.map.local_def_id(item.id)); + let stab = stability::lookup_stability(tcx, ecx.tcx.map.local_def_id(item.id)); + let depr = stability::lookup_deprecation(tcx, ecx.tcx.map.local_def_id(item.id)); match item.node { hir::ItemStatic(_, m, _) => { @@ -949,6 +972,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_path(rbml_w, path); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); encode_attributes(rbml_w, &item.attrs); rbml_w.end_tag(); } @@ -964,6 +988,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item)); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); rbml_w.end_tag(); } hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { @@ -986,6 +1011,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_constness(rbml_w, constness); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); encode_method_argument_names(rbml_w, &**decl); rbml_w.end_tag(); } @@ -1015,6 +1041,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); rbml_w.end_tag(); } hir::ItemTy(..) => { @@ -1027,6 +1054,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_path(rbml_w, path); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); rbml_w.end_tag(); } hir::ItemEnum(ref enum_definition, _) => { @@ -1051,6 +1079,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); rbml_w.end_tag(); encode_enum_variant_info(ecx, @@ -1077,6 +1106,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_attributes(rbml_w, &item.attrs); encode_path(rbml_w, path.clone()); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); encode_visibility(rbml_w, vis); encode_repr_attrs(rbml_w, ecx, &item.attrs); @@ -1167,6 +1197,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } encode_path(rbml_w, path.clone()); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); rbml_w.end_tag(); // Iterate down the trait items, emitting them. We rely on the @@ -1236,6 +1267,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_attributes(rbml_w, &item.attrs); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { rbml_w.start_tag(tag_item_trait_item); match method_def_id { @@ -1274,8 +1306,10 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_parent_item(rbml_w, def_id); - let stab = stability::lookup(tcx, item_def_id.def_id()); + let stab = stability::lookup_stability(tcx, item_def_id.def_id()); + let depr = stability::lookup_deprecation(tcx, item_def_id.def_id()); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); let trait_item_type = tcx.impl_or_trait_item(item_def_id.def_id()); @@ -1407,8 +1441,10 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem)); } encode_attributes(rbml_w, &*nitem.attrs); - let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); + let stab = stability::lookup_stability(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); + let depr = stability::lookup_deprecation(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); encode_symbol(ecx, rbml_w, nitem.id); encode_method_argument_names(rbml_w, &*fndecl); } @@ -1420,8 +1456,10 @@ fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, } encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id); encode_attributes(rbml_w, &*nitem.attrs); - let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); + let stab = stability::lookup_stability(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); + let depr = stability::lookup_deprecation(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id)); encode_stability(rbml_w, stab); + encode_deprecation(rbml_w, depr); encode_symbol(ecx, rbml_w, nitem.id); encode_name(rbml_w, nitem.name); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 40e71466709..5c88576acb7 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -120,7 +120,7 @@ fn try_inline_def(cx: &DocContext, tcx: &ty::ctxt, attrs: load_attrs(cx, tcx, did), inner: inner, visibility: Some(hir::Public), - stability: stability::lookup(tcx, did).clean(cx), + stability: stability::lookup_stability(tcx, did).clean(cx), def_id: did, }); Some(ret) @@ -303,7 +303,7 @@ pub fn build_impl(cx: &DocContext, name: None, attrs: attrs, visibility: Some(hir::Inherited), - stability: stability::lookup(tcx, did).clean(cx), + stability: stability::lookup_stability(tcx, did).clean(cx), def_id: did, }); } @@ -333,7 +333,7 @@ pub fn build_impl(cx: &DocContext, source: clean::Span::empty(), attrs: vec![], visibility: None, - stability: stability::lookup(tcx, did).clean(cx), + stability: stability::lookup_stability(tcx, did).clean(cx), def_id: did }) } @@ -381,7 +381,7 @@ pub fn build_impl(cx: &DocContext, source: clean::Span::empty(), attrs: vec![], visibility: None, - stability: stability::lookup(tcx, did).clean(cx), + stability: stability::lookup_stability(tcx, did).clean(cx), def_id: did }) } @@ -414,7 +414,7 @@ pub fn build_impl(cx: &DocContext, name: None, attrs: attrs, visibility: Some(hir::Inherited), - stability: stability::lookup(tcx, did).clean(cx), + stability: stability::lookup_stability(tcx, did).clean(cx), def_id: did, }); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 1336acb6b03..942cc135aa8 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -62,7 +62,7 @@ mod simplify; // extract the stability index for a node from tcx, if possible fn get_stability(cx: &DocContext, def_id: DefId) -> Option { - cx.tcx_opt().and_then(|tcx| stability::lookup(tcx, def_id)).clean(cx) + cx.tcx_opt().and_then(|tcx| stability::lookup_stability(tcx, def_id)).clean(cx) } pub trait Clean { @@ -2689,12 +2689,12 @@ impl Clean for attr::Stability { attr::Stable {ref since} => since.to_string(), _ => "".to_string(), }, - deprecated_since: match self.depr { - Some(attr::Deprecation {ref since, ..}) => since.to_string(), + deprecated_since: match self.rustc_depr { + Some(attr::RustcDeprecation {ref since, ..}) => since.to_string(), _=> "".to_string(), }, reason: { - if let Some(ref depr) = self.depr { + if let Some(ref depr) = self.rustc_depr { depr.reason.to_string() } else if let attr::Unstable {reason: Some(ref reason), ..} = self.level { reason.to_string() @@ -2782,7 +2782,7 @@ impl<'tcx> Clean for ty::AssociatedType<'tcx> { inner: AssociatedTypeItem(bounds, self.ty.clean(cx)), visibility: self.vis.clean(cx), def_id: self.def_id, - stability: stability::lookup(cx.tcx(), self.def_id).clean(cx), + stability: stability::lookup_stability(cx.tcx(), self.def_id).clean(cx), } } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 17291233e11..89527c54a38 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -64,7 +64,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { fn stability(&self, id: ast::NodeId) -> Option { self.cx.tcx_opt().and_then(|tcx| { self.cx.map.opt_local_def_id(id) - .and_then(|def_id| stability::lookup(tcx, def_id)) + .and_then(|def_id| stability::lookup_stability(tcx, def_id)) .cloned() }) } 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"), } } diff --git a/src/test/auxiliary/deprecation-lint.rs b/src/test/auxiliary/deprecation-lint.rs new file mode 100644 index 00000000000..61c91590b31 --- /dev/null +++ b/src/test/auxiliary/deprecation-lint.rs @@ -0,0 +1,87 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(deprecated)] + +#[deprecated(since = "1.0.0", note = "text")] +pub fn deprecated() {} +#[deprecated(since = "1.0.0", note = "text")] +pub fn deprecated_text() {} + +pub struct MethodTester; + +impl MethodTester { + #[deprecated(since = "1.0.0", note = "text")] + pub fn method_deprecated(&self) {} + #[deprecated(since = "1.0.0", note = "text")] + pub fn method_deprecated_text(&self) {} +} + +pub trait Trait { + #[deprecated(since = "1.0.0", note = "text")] + fn trait_deprecated(&self) {} + #[deprecated(since = "1.0.0", note = "text")] + fn trait_deprecated_text(&self) {} +} + +impl Trait for MethodTester {} + +#[deprecated(since = "1.0.0", note = "text")] +pub struct DeprecatedStruct { + pub i: isize +} + +#[deprecated(since = "1.0.0", note = "text")] +pub struct DeprecatedUnitStruct; + +pub enum Enum { + #[deprecated(since = "1.0.0", note = "text")] + DeprecatedVariant, +} + +#[deprecated(since = "1.0.0", note = "text")] +pub struct DeprecatedTupleStruct(pub isize); + +pub struct Stable { + #[deprecated(since = "1.0.0", note = "text")] + pub override2: u8, +} + +pub struct Stable2(pub u8, pub u8, #[deprecated(since = "1.0.0", note = "text")] pub u8); + +#[deprecated(since = "1.0.0", note = "text")] +pub struct Deprecated { + pub inherit: u8, +} + +#[deprecated(since = "1.0.0", note = "text")] +pub struct Deprecated2(pub u8, + pub u8, + pub u8); + +#[deprecated(since = "1.0.0", note = "text")] +pub mod deprecated_mod { + pub fn deprecated() {} +} + +#[macro_export] +macro_rules! macro_test { + () => (deprecated()); +} + +#[macro_export] +macro_rules! macro_test_arg { + ($func:expr) => ($func); +} + +#[macro_export] +macro_rules! macro_test_arg_nested { + ($func:ident) => (macro_test_arg!($func())); +} diff --git a/src/test/compile-fail/deprecation-in-staged-api.rs b/src/test/compile-fail/deprecation-in-staged-api.rs new file mode 100644 index 00000000000..4f4aed21f99 --- /dev/null +++ b/src/test/compile-fail/deprecation-in-staged-api.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// #[deprecated] can't be used in staged api + +#![feature(deprecated, staged_api)] + +#![stable(feature = "test_feature", since = "1.0.0")] + +#[deprecated] +fn main() { } //~ERROR `#[deprecated]` cannot be used in staged api diff --git a/src/test/compile-fail/deprecation-lint-2.rs b/src/test/compile-fail/deprecation-lint-2.rs new file mode 100644 index 00000000000..2817e06652a --- /dev/null +++ b/src/test/compile-fail/deprecation-lint-2.rs @@ -0,0 +1,23 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:deprecation-lint.rs +// error-pattern: use of deprecated item + +#![deny(deprecated)] + +#[macro_use] +extern crate deprecation_lint; + +use deprecation_lint::*; + +fn main() { + macro_test!(); +} diff --git a/src/test/compile-fail/deprecation-lint-3.rs b/src/test/compile-fail/deprecation-lint-3.rs new file mode 100644 index 00000000000..7faaa181d39 --- /dev/null +++ b/src/test/compile-fail/deprecation-lint-3.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:deprecation-lint.rs +// error-pattern: use of deprecated item + +#![deny(deprecated)] +#![allow(warnings)] + +#[macro_use] +extern crate deprecation_lint; + +use deprecation_lint::*; + +fn main() { + macro_test_arg_nested!(deprecated_text); +} diff --git a/src/test/compile-fail/deprecation-lint.rs b/src/test/compile-fail/deprecation-lint.rs new file mode 100644 index 00000000000..db6d5fd63e5 --- /dev/null +++ b/src/test/compile-fail/deprecation-lint.rs @@ -0,0 +1,384 @@ +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:deprecation-lint.rs + +#![feature(deprecated)] + +#![deny(deprecated)] +#![allow(warnings)] + +#[macro_use] +extern crate deprecation_lint; + +mod cross_crate { + use deprecation_lint::*; + + fn test() { + type Foo = MethodTester; + let foo = MethodTester; + + deprecated(); //~ ERROR use of deprecated item + foo.method_deprecated(); //~ ERROR use of deprecated item + Foo::method_deprecated(&foo); //~ ERROR use of deprecated item + ::method_deprecated(&foo); //~ ERROR use of deprecated item + foo.trait_deprecated(); //~ ERROR use of deprecated item + Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + + deprecated_text(); //~ ERROR use of deprecated item: text + foo.method_deprecated_text(); //~ ERROR use of deprecated item: text + Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + + let _ = DeprecatedStruct { //~ ERROR use of deprecated item + i: 0 //~ ERROR use of deprecated item + }; + + let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item + + let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item + + let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item + + // At the moment, the lint checker only checks stability in + // in the arguments of macros. + // Eventually, we will want to lint the contents of the + // macro in the module *defining* it. Also, stability levels + // on macros themselves are not yet linted. + macro_test_arg!(deprecated_text()); //~ ERROR use of deprecated item: text + macro_test_arg!(macro_test_arg!(deprecated_text())); //~ ERROR use of deprecated item: text + } + + fn test_method_param(foo: Foo) { + foo.trait_deprecated(); //~ ERROR use of deprecated item + Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + } + + fn test_method_object(foo: &Trait) { + foo.trait_deprecated(); //~ ERROR use of deprecated item + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + } + + pub fn foo() { + let x = Stable { + override2: 3, + //~^ ERROR use of deprecated item + }; + + let _ = x.override2; + //~^ ERROR use of deprecated item + + let Stable { + override2: _ + //~^ ERROR use of deprecated item + } = x; + // all fine + let Stable { .. } = x; + + let x = Stable2(1, 2, 3); + + let _ = x.2; + //~^ ERROR use of deprecated item + + let Stable2(_, + _, + _) + //~^ ERROR use of deprecated item + = x; + // all fine + let Stable2(..) = x; + + let x = Deprecated { + //~^ ERROR use of deprecated item + inherit: 1, + //~^ ERROR use of deprecated item + }; + + let _ = x.inherit; + //~^ ERROR use of deprecated item + + let Deprecated { + //~^ ERROR use of deprecated item + inherit: _, + //~^ ERROR use of deprecated item + } = x; + + let Deprecated + //~^ ERROR use of deprecated item + { .. } = x; + + let x = Deprecated2(1, 2, 3); + //~^ ERROR use of deprecated item + + let _ = x.0; + //~^ ERROR use of deprecated item + let _ = x.1; + //~^ ERROR use of deprecated item + let _ = x.2; + //~^ ERROR use of deprecated item + + let Deprecated2 + //~^ ERROR use of deprecated item + (_, + //~^ ERROR use of deprecated item + _, + //~^ ERROR use of deprecated item + _) + //~^ ERROR use of deprecated item + = x; + let Deprecated2 + //~^ ERROR use of deprecated item + // the patterns are all fine: + (..) = x; + } +} + +mod inheritance { + use deprecation_lint::*; + + fn test_inheritance() { + deprecated_mod::deprecated(); //~ ERROR use of deprecated item + } +} + +mod this_crate { + #[deprecated(since = "1.0.0", note = "text")] + pub fn deprecated() {} + #[deprecated(since = "1.0.0", note = "text")] + pub fn deprecated_text() {} + + pub struct MethodTester; + + impl MethodTester { + #[deprecated(since = "1.0.0", note = "text")] + pub fn method_deprecated(&self) {} + #[deprecated(since = "1.0.0", note = "text")] + pub fn method_deprecated_text(&self) {} + } + + pub trait Trait { + #[deprecated(since = "1.0.0", note = "text")] + fn trait_deprecated(&self) {} + #[deprecated(since = "1.0.0", note = "text")] + fn trait_deprecated_text(&self) {} + } + + impl Trait for MethodTester {} + + #[deprecated(since = "1.0.0", note = "text")] + pub struct DeprecatedStruct { + i: isize + } + pub struct UnstableStruct { + i: isize + } + pub struct StableStruct { + i: isize + } + + #[deprecated(since = "1.0.0", note = "text")] + pub struct DeprecatedUnitStruct; + + pub enum Enum { + #[deprecated(since = "1.0.0", note = "text")] + DeprecatedVariant, + } + + #[deprecated(since = "1.0.0", note = "text")] + pub struct DeprecatedTupleStruct(isize); + + fn test() { + // Only the deprecated cases of the following should generate + // errors, because other stability attributes now have meaning + // only *across* crates, not within a single crate. + + type Foo = MethodTester; + let foo = MethodTester; + + deprecated(); //~ ERROR use of deprecated item + foo.method_deprecated(); //~ ERROR use of deprecated item + Foo::method_deprecated(&foo); //~ ERROR use of deprecated item + ::method_deprecated(&foo); //~ ERROR use of deprecated item + foo.trait_deprecated(); //~ ERROR use of deprecated item + Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + + deprecated_text(); //~ ERROR use of deprecated item: text + foo.method_deprecated_text(); //~ ERROR use of deprecated item: text + Foo::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::method_deprecated_text(&foo); //~ ERROR use of deprecated item: text + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + + let _ = DeprecatedStruct { + //~^ ERROR use of deprecated item + i: 0 //~ ERROR use of deprecated item + }; + + let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item + + let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item + + let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item + } + + fn test_method_param(foo: Foo) { + foo.trait_deprecated(); //~ ERROR use of deprecated item + Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + ::trait_deprecated(&foo); //~ ERROR use of deprecated item + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + Trait::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + ::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text + } + + fn test_method_object(foo: &Trait) { + foo.trait_deprecated(); //~ ERROR use of deprecated item + foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text + } + + #[deprecated(since = "1.0.0", note = "text")] + fn test_fn_body() { + fn fn_in_body() {} + fn_in_body(); //~ ERROR use of deprecated item: text + } + + impl MethodTester { + #[deprecated(since = "1.0.0", note = "text")] + fn test_method_body(&self) { + fn fn_in_body() {} + fn_in_body(); //~ ERROR use of deprecated item: text + } + } + + #[deprecated(since = "1.0.0", note = "text")] + pub trait DeprecatedTrait { + fn dummy(&self) { } + } + + struct S; + + impl DeprecatedTrait for S { } //~ ERROR use of deprecated item + + trait LocalTrait : DeprecatedTrait { } //~ ERROR use of deprecated item +} + +mod this_crate2 { + struct Stable { + #[deprecated(since = "1.0.0", note = "text")] + override2: u8, + } + + struct Stable2(u8, + u8, + #[deprecated(since = "1.0.0", note = "text")] u8); + + #[deprecated(since = "1.0.0", note = "text")] + struct Deprecated { + inherit: u8, + } + + #[deprecated(since = "1.0.0", note = "text")] + struct Deprecated2(u8, + u8, + u8); + + pub fn foo() { + let x = Stable { + override2: 3, + //~^ ERROR use of deprecated item + }; + + let _ = x.override2; + //~^ ERROR use of deprecated item + + let Stable { + override2: _ + //~^ ERROR use of deprecated item + } = x; + // all fine + let Stable { .. } = x; + + let x = Stable2(1, 2, 3); + + let _ = x.2; + //~^ ERROR use of deprecated item + + let Stable2(_, + _, + _) + //~^ ERROR use of deprecated item + = x; + // all fine + let Stable2(..) = x; + + let x = Deprecated { + //~^ ERROR use of deprecated item + inherit: 1, + //~^ ERROR use of deprecated item + }; + + let _ = x.inherit; + //~^ ERROR use of deprecated item + + let Deprecated { + //~^ ERROR use of deprecated item + inherit: _, + //~^ ERROR use of deprecated item + } = x; + + let Deprecated + //~^ ERROR use of deprecated item + // the patterns are all fine: + { .. } = x; + + let x = Deprecated2(1, 2, 3); + //~^ ERROR use of deprecated item + + let _ = x.0; + //~^ ERROR use of deprecated item + let _ = x.1; + //~^ ERROR use of deprecated item + let _ = x.2; + //~^ ERROR use of deprecated item + + let Deprecated2 + //~^ ERROR use of deprecated item + (_, + //~^ ERROR use of deprecated item + _, + //~^ ERROR use of deprecated item + _) + //~^ ERROR use of deprecated item + = x; + let Deprecated2 + //~^ ERROR use of deprecated item + // the patterns are all fine: + (..) = x; + } +} + +fn main() {} diff --git a/src/test/compile-fail/deprecation-sanity.rs b/src/test/compile-fail/deprecation-sanity.rs new file mode 100644 index 00000000000..6ee5cd2c7e3 --- /dev/null +++ b/src/test/compile-fail/deprecation-sanity.rs @@ -0,0 +1,39 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Various checks that deprecation attributes are used correctly + +#![feature(deprecated)] + +mod bogus_attribute_types_1 { + #[deprecated(since = "a", note = "a", reason)] //~ ERROR unknown meta item 'reason' + fn f1() { } + + #[deprecated(since = "a", note)] //~ ERROR incorrect meta item + fn f2() { } + + #[deprecated(since, note = "a")] //~ ERROR incorrect meta item + fn f3() { } + + #[deprecated(since = "a", note(b))] //~ ERROR incorrect meta item + fn f5() { } + + #[deprecated(since(b), note = "a")] //~ ERROR incorrect meta item + fn f6() { } +} + +#[deprecated(since = "a", note = "b")] +#[deprecated(since = "a", note = "b")] +fn multiple1() { } //~ ERROR multiple deprecated attributes + +#[deprecated(since = "a", since = "b", note = "c")] //~ ERROR multiple 'since' items +fn f1() { } + +fn main() { }