提交 e3ed7b05 编写于 作者: V Vadim Petrochenkov

Implement `#[deprecated]` attribute (RFC 1270)

上级 45a73c8c
......@@ -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
......
......@@ -135,6 +135,7 @@ pub enum FoundAst<'ast> {
pub trait CrateStore<'tcx> : Any {
// item info
fn stability(&self, def: DefId) -> Option<attr::Stability>;
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>;
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 fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
// item info
fn stability(&self, def: DefId) -> Option<attr::Stability> { unimplemented!() }
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { 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)
......
......@@ -25,7 +25,7 @@
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<Option<&'tcx Stability>>,
stab_map: DefIdMap<Option<&'tcx Stability>>,
depr_map: DefIdMap<Option<Deprecation>>,
/// Maps for each crate whether it is part of the staged API.
staged_api: FnvHashMap<ast::CrateNum, bool>
......@@ -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<Deprecation>,
access_levels: &'a AccessLevels,
in_trait_impl: bool,
in_enum: bool,
......@@ -86,22 +88,26 @@ fn annotate<F>(&mut self, id: NodeId, attrs: &Vec<Attribute>,
{
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 @@ fn annotate<F>(&mut self, id: NodeId, attrs: &Vec<Attribute>,
// 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::<u64>(), stab_v.parse()) {
......@@ -134,20 +140,20 @@ fn annotate<F>(&mut self, id: NodeId, attrs: &Vec<Attribute>,
}
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 @@ fn annotate<F>(&mut self, id: NodeId, attrs: &Vec<Attribute>,
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 @@ pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &Crate, access_levels: &Acc
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 @@ pub fn new(krate: &Crate) -> 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<Deprecation>) {
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 @@ fn visit_item(&mut self, item: &hir::Item) {
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 @@ fn visit_block(&mut self, b: &hir::Block) {
/// 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<Deprecation>)) {
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<Deprecation>)) {
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<Deprecation>)) {
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<Deprecation>)) {
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<Deprecation>)) {
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<Deprecation>)) {
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<Deprecation> {
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<Deprecation> {
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
......
......@@ -575,74 +575,71 @@ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
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<attr::Deprecation>) {
// Deprecated attributes apply in-crate and cross-crate.
let (lint, label) = match *stability {
Some(&attr::Stability { depr: Some(_), .. }) =>
(DEPRECATED, "deprecated"),
_ => return
};
output(cx, span, stability, lint, label);
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))
}
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));
}
}
......
......@@ -124,7 +124,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
UnusedAllocation,
MissingCopyImplementations,
UnstableFeatures,
Stability,
Deprecated,
UnconditionalRecursion,
InvalidNoMangleItems,
PluginAsLibrary,
......
......@@ -237,6 +237,8 @@ pub enum astencode_tag { // Reserves 0x50 -- 0x6f
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!(
......
......@@ -42,6 +42,12 @@ fn stability(&self, def: DefId) -> Option<attr::Stability>
decoder::get_stability(&*cdata, def.index)
}
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>
{
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());
......
......@@ -526,6 +526,14 @@ pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option<attr::Stability> {
})
}
pub fn get_deprecation(cdata: Cmd, id: DefIndex) -> Option<attr::Deprecation> {
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<attr::ReprAttr> {
let item = cdata.lookup_item(id);
match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| {
......
......@@ -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<attr::Deprecation>) {
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<XRef<'tcx>, 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);
}
......
......@@ -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,
});
......
......@@ -62,7 +62,7 @@
// extract the stability index for a node from tcx, if possible
fn get_stability(cx: &DocContext, def_id: DefId) -> Option<Stability> {
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<T> {
......@@ -2689,12 +2689,12 @@ fn clean(&self, _: &DocContext) -> 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 @@ fn clean(&self, cx: &DocContext) -> Item {
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),
}
}
}
......
......@@ -64,7 +64,7 @@ pub fn new(cx: &'a core::DocContext<'a, 'tcx>,
fn stability(&self, id: ast::NodeId) -> Option<attr::Stability> {
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()
})
}
......
......@@ -398,7 +398,7 @@ pub fn cfg_matches<T: CfgDiag>(cfgs: &[P<MetaItem>],
pub struct Stability {
pub level: StabilityLevel,
pub feature: InternedString,
pub depr: Option<Deprecation>,
pub rustc_depr: Option<RustcDeprecation>,
}
/// 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<InternedString>,
pub note: Option<InternedString>,
}
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<Item = &'a Attribute>
{
let mut stab: Option<Stability> = None;
let mut depr: Option<Deprecation> = None;
let mut rustc_depr: Option<RustcDeprecation> = 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<Deprecation>
where I: Iterator<Item = &'a Attribute>
{
let mut depr: Option<Deprecation> = 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<InternedString>| {
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<Stability> {
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<Deprecation> {
find_deprecation_generic(diagnostic, attrs.iter(), item_sp)
}
pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P<MetaItem>]) {
let mut set = HashSet::new();
for meta in metas {
......
......@@ -230,6 +230,9 @@
// 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 @@ enum Status {
("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 @@ pub fn new() -> Features {
braced_empty_structs: false,
staged_api: false,
stmt_expr_attributes: false,
deprecated: false,
}
}
}
......@@ -1151,6 +1157,7 @@ fn check_crate_inner<F>(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"),
}
}
......
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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()));
}
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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!();
}
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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);
}
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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
<Foo>::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
<Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
<Foo as Trait>::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
<Foo>::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
<Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
<Foo as Trait>::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: Trait>(foo: Foo) {
foo.trait_deprecated(); //~ ERROR use of deprecated item
Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item
<Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
<Foo as Trait>::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
<Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
<Foo as Trait>::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
<Foo>::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
<Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
<Foo as Trait>::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
<Foo>::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
<Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
<Foo as Trait>::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: Trait>(foo: Foo) {
foo.trait_deprecated(); //~ ERROR use of deprecated item
Trait::trait_deprecated(&foo); //~ ERROR use of deprecated item
<Foo>::trait_deprecated(&foo); //~ ERROR use of deprecated item
<Foo as Trait>::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
<Foo>::trait_deprecated_text(&foo); //~ ERROR use of deprecated item: text
<Foo as Trait>::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() {}
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() { }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册