about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-12-16 08:15:23 +0000
committerbors <bors@rust-lang.org>2015-12-16 08:15:23 +0000
commitac2c5ff0241bdd090af11a74566bd00f03ae8ae0 (patch)
tree780d1609c300fedd2dd9c7af17a0366d185c61aa
parent9ace0a46de9b47cfa93c4e906805455b221e2881 (diff)
parent67a978411a2009093bb40c4f1320a08d2a28b6c7 (diff)
Auto merge of #30206 - petrochenkov:newdepr, r=brson
Closes https://github.com/rust-lang/rust/issues/29935

The attributes `deprecated` and `rustc_deprecated` are completely independent in this implementation and it leads to some noticeable code duplication. Representing `deprecated` as
```
Stability {
    level: Stable { since: "" },
    feature: "",
    depr: Some(Deprecation),
}
```
or, contrariwise, splitting rustc_deprecation from stability makes most of the duplication go away.
I can do this refactoring, but before doing it I must be sure, that further divergence of `deprecated` and `rustc_deprecated` is certainly not a goal.

cc @llogiq
-rw-r--r--src/doc/reference.md2
-rw-r--r--src/librustc/middle/cstore.rs2
-rw-r--r--src/librustc/middle/stability.rs158
-rw-r--r--src/librustc_lint/builtin.rs63
-rw-r--r--src/librustc_lint/lib.rs2
-rw-r--r--src/librustc_metadata/common.rs2
-rw-r--r--src/librustc_metadata/csearch.rs6
-rw-r--r--src/librustc_metadata/decoder.rs8
-rw-r--r--src/librustc_metadata/encoder.rs60
-rw-r--r--src/librustdoc/clean/inline.rs15
-rw-r--r--src/librustdoc/clean/mod.rs55
-rw-r--r--src/librustdoc/doctree.rs12
-rw-r--r--src/librustdoc/fold.rs5
-rw-r--r--src/librustdoc/html/render.rs24
-rw-r--r--src/librustdoc/visit_ast.rs20
-rw-r--r--src/libsyntax/attr.rs91
-rw-r--r--src/libsyntax/feature_gate.rs7
-rw-r--r--src/test/auxiliary/deprecation-lint.rs90
-rw-r--r--src/test/auxiliary/lint_stability.rs6
-rw-r--r--src/test/compile-fail/deprecation-in-staged-api.rs18
-rw-r--r--src/test/compile-fail/deprecation-lint-2.rs23
-rw-r--r--src/test/compile-fail/deprecation-lint-3.rs24
-rw-r--r--src/test/compile-fail/deprecation-lint.rs389
-rw-r--r--src/test/compile-fail/deprecation-sanity.rs39
-rw-r--r--src/test/compile-fail/lint-stability.rs3
-rw-r--r--src/test/rustdoc/deprecated.rs16
26 files changed, 1003 insertions, 137 deletions
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<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 struct DummyCrateStore;
 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)
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 0d92c3da83c..31158901775 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<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 @@ 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::<u64>(), 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;
                     }
                 }
@@ -167,7 +173,26 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
                                                          outside of the standard library");
                 }
             }
-            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 +294,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 +317,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 +354,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 +426,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 +472,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<Deprecation>)) {
     match item.node {
         hir::ItemExternCrate(_) => {
             // compiler-generated `extern crate` items have a dummy span.
@@ -478,7 +509,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 +570,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 +582,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 +593,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 +622,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,47 +658,42 @@ 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> {
-    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)
-        }
-        _ => {}
+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 item_stab = if id.is_local() {
+    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);
+    if id.is_local() {
         None // The stability cache is filled partially lazily
     } else {
         tcx.sess.cstore.stability(id).map(|st| tcx.intern_stability(st))
-    };
-
-    item_stab.or_else(|| {
-        if tcx.is_impl(id) {
-            if let Some(trait_id) = tcx.trait_id_of_impl(id) {
-                // FIXME (#18969): for the time being, simply use the
-                // stability of the trait to determine the stability of any
-                // unmarked impls for it. See FIXME above for more details.
+    }
+}
 
-                debug!("lookup: trait_id={:?}", trait_id);
-                return lookup(tcx, trait_id);
-            }
-        }
-        None
-    })
+fn lookup_deprecation_uncached<'tcx>(tcx: &ty::ctxt<'tcx>, id: DefId) -> Option<Deprecation> {
+    debug!("lookup(id={:?})", id);
+    if id.is_local() {
+        None // The stability cache is filled partially lazily
+    } else {
+        tcx.sess.cstore.deprecation(id)
+    }
 }
 
 /// Given the list of enabled features that were not language features (i.e. that
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 90d9bcfffee..e403e6d067a 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 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));
     }
 }
 
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<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());
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<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| {
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<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);
       }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 40e71466709..c0f62cddb98 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -120,7 +120,8 @@ 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),
+        deprecation: stability::lookup_deprecation(tcx, did).clean(cx),
         def_id: did,
     });
     Some(ret)
@@ -303,7 +304,8 @@ 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),
+            deprecation: stability::lookup_deprecation(tcx, did).clean(cx),
             def_id: did,
         });
     }
@@ -333,7 +335,8 @@ 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),
+                    deprecation: stability::lookup_deprecation(tcx, did).clean(cx),
                     def_id: did
                 })
             }
@@ -381,7 +384,8 @@ 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),
+                    deprecation: stability::lookup_deprecation(tcx, did).clean(cx),
                     def_id: did
                 })
             }
@@ -414,7 +418,8 @@ 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),
+        deprecation: stability::lookup_deprecation(tcx, did).clean(cx),
         def_id: did,
     });
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 1336acb6b03..52eeb781b31 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -62,7 +62,11 @@ mod simplify;
 
 // 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)
+}
+
+fn get_deprecation(cx: &DocContext, def_id: DefId) -> Option<Deprecation> {
+    cx.tcx_opt().and_then(|tcx| stability::lookup_deprecation(tcx, def_id)).clean(cx)
 }
 
 pub trait Clean<T> {
@@ -188,6 +192,7 @@ impl<'a, 'tcx> Clean<Crate> for visit_ast::RustdocVisitor<'a, 'tcx> {
                     attrs: child.attrs.clone(),
                     visibility: Some(hir::Public),
                     stability: None,
+                    deprecation: None,
                     def_id: DefId::local(prim.to_def_index()),
                     inner: PrimitiveItem(prim),
                 });
@@ -254,6 +259,7 @@ pub struct Item {
     pub visibility: Option<Visibility>,
     pub def_id: DefId,
     pub stability: Option<Stability>,
+    pub deprecation: Option<Deprecation>,
 }
 
 impl Item {
@@ -417,6 +423,7 @@ impl Clean<Item> for doctree::Module {
             source: whence.clean(cx),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
+            deprecation: self.depr.clean(cx),
             def_id: cx.map.local_def_id(self.id),
             inner: ModuleItem(Module {
                is_crate: self.is_crate,
@@ -1078,6 +1085,7 @@ impl Clean<Item> for doctree::Function {
             source: self.whence.clean(cx),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
+            deprecation: self.depr.clean(cx),
             def_id: cx.map.local_def_id(self.id),
             inner: FunctionItem(Function {
                 decl: self.decl.clean(cx),
@@ -1204,6 +1212,7 @@ impl Clean<Item> for doctree::Trait {
             def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
+            deprecation: self.depr.clean(cx),
             inner: TraitItem(Trait {
                 unsafety: self.unsafety,
                 items: self.items.clean(cx),
@@ -1254,6 +1263,7 @@ impl Clean<Item> for hir::TraitItem {
             def_id: cx.map.local_def_id(self.id),
             visibility: None,
             stability: get_stability(cx, cx.map.local_def_id(self.id)),
+            deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
             inner: inner
         }
     }
@@ -1287,6 +1297,7 @@ impl Clean<Item> for hir::ImplItem {
             def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: get_stability(cx, cx.map.local_def_id(self.id)),
+            deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
             inner: inner
         }
     }
@@ -1357,6 +1368,7 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> {
             name: Some(self.name.clean(cx)),
             visibility: Some(hir::Inherited),
             stability: get_stability(cx, self.def_id),
+            deprecation: get_deprecation(cx, self.def_id),
             def_id: self.def_id,
             attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
             source: Span::empty(),
@@ -1715,6 +1727,7 @@ impl Clean<Item> for hir::StructField {
             source: self.span.clean(cx),
             visibility: Some(vis),
             stability: get_stability(cx, cx.map.local_def_id(self.node.id)),
+            deprecation: get_deprecation(cx, cx.map.local_def_id(self.node.id)),
             def_id: cx.map.local_def_id(self.node.id),
             inner: StructFieldItem(TypedStructField(self.node.ty.clean(cx))),
         }
@@ -1740,6 +1753,7 @@ impl<'tcx> Clean<Item> for ty::FieldDefData<'tcx, 'static> {
             source: Span::empty(),
             visibility: Some(self.vis),
             stability: get_stability(cx, self.did),
+            deprecation: get_deprecation(cx, self.did),
             def_id: self.did,
             inner: StructFieldItem(TypedStructField(self.unsubst_ty().clean(cx))),
         }
@@ -1771,6 +1785,7 @@ impl Clean<Item> for doctree::Struct {
             def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
+            deprecation: self.depr.clean(cx),
             inner: StructItem(Struct {
                 struct_type: self.struct_type,
                 generics: self.generics.clean(cx),
@@ -1817,6 +1832,7 @@ impl Clean<Item> for doctree::Enum {
             def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
+            deprecation: self.depr.clean(cx),
             inner: EnumItem(Enum {
                 variants: self.variants.clean(cx),
                 generics: self.generics.clean(cx),
@@ -1839,6 +1855,7 @@ impl Clean<Item> for doctree::Variant {
             source: self.whence.clean(cx),
             visibility: None,
             stability: self.stab.clean(cx),
+            deprecation: self.depr.clean(cx),
             def_id: cx.map.local_def_id(self.def.id()),
             inner: VariantItem(Variant {
                 kind: struct_def_to_variant_kind(&self.def, cx),
@@ -1876,6 +1893,7 @@ impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
                             //        at the needed information here.
                             def_id: self.did,
                             stability: get_stability(cx, self.did),
+                            deprecation: get_deprecation(cx, self.did),
                             inner: StructFieldItem(
                                 TypedStructField(field.unsubst_ty().clean(cx))
                             )
@@ -1892,6 +1910,7 @@ impl<'tcx> Clean<Item> for ty::VariantDefData<'tcx, 'static> {
             def_id: self.did,
             inner: VariantItem(Variant { kind: kind }),
             stability: get_stability(cx, self.did),
+            deprecation: get_deprecation(cx, self.did),
         }
     }
 }
@@ -2067,6 +2086,7 @@ impl Clean<Item> for doctree::Typedef {
             def_id: cx.map.local_def_id(self.id.clone()),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
+            deprecation: self.depr.clean(cx),
             inner: TypedefItem(Typedef {
                 type_: self.ty.clean(cx),
                 generics: self.gen.clean(cx),
@@ -2118,6 +2138,7 @@ impl Clean<Item> for doctree::Static {
             def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
+            deprecation: self.depr.clean(cx),
             inner: StaticItem(Static {
                 type_: self.type_.clean(cx),
                 mutability: self.mutability.clean(cx),
@@ -2142,6 +2163,7 @@ impl Clean<Item> for doctree::Constant {
             def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
+            deprecation: self.depr.clean(cx),
             inner: ConstantItem(Constant {
                 type_: self.type_.clean(cx),
                 expr: self.expr.span.to_src(cx),
@@ -2216,6 +2238,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
             def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
+            deprecation: self.depr.clean(cx),
             inner: ImplItem(Impl {
                 unsafety: self.unsafety,
                 generics: self.generics.clean(cx),
@@ -2298,6 +2321,7 @@ impl Clean<Item> for doctree::DefaultImpl {
             def_id: cx.map.local_def_id(self.id),
             visibility: Some(hir::Public),
             stability: None,
+            deprecation: None,
             inner: DefaultImplItem(DefaultImpl {
                 unsafety: self.unsafety,
                 trait_: self.trait_.clean(cx),
@@ -2315,6 +2339,7 @@ impl Clean<Item> for doctree::ExternCrate {
             def_id: cx.map.local_def_id(0),
             visibility: self.vis.clean(cx),
             stability: None,
+            deprecation: None,
             inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
         }
     }
@@ -2380,6 +2405,7 @@ impl Clean<Vec<Item>> for doctree::Import {
             def_id: cx.map.local_def_id(0),
             visibility: self.vis.clean(cx),
             stability: None,
+            deprecation: None,
             inner: ImportItem(inner)
         });
         ret
@@ -2466,6 +2492,7 @@ impl Clean<Item> for hir::ForeignItem {
             def_id: cx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: get_stability(cx, cx.map.local_def_id(self.id)),
+            deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
             inner: inner,
         }
     }
@@ -2659,6 +2686,7 @@ impl Clean<Item> for doctree::Macro {
             source: self.whence.clean(cx),
             visibility: hir::Public.clean(cx),
             stability: self.stab.clean(cx),
+            deprecation: self.depr.clean(cx),
             def_id: cx.map.local_def_id(self.id),
             inner: MacroItem(Macro {
                 source: format!("macro_rules! {} {{\n{}}}",
@@ -2680,6 +2708,12 @@ pub struct Stability {
     pub issue: Option<u32>
 }
 
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub struct Deprecation {
+    pub since: String,
+    pub note: String,
+}
+
 impl Clean<Stability> for attr::Stability {
     fn clean(&self, _: &DocContext) -> Stability {
         Stability {
@@ -2689,12 +2723,12 @@ impl Clean<Stability> 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()
@@ -2716,6 +2750,15 @@ impl<'a> Clean<Stability> for &'a attr::Stability {
     }
 }
 
+impl Clean<Deprecation> for attr::Deprecation {
+    fn clean(&self, _: &DocContext) -> Deprecation {
+        Deprecation {
+            since: self.since.as_ref().map_or("".to_string(), |s| s.to_string()),
+            note: self.note.as_ref().map_or("".to_string(), |s| s.to_string()),
+        }
+    }
+}
+
 impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
     fn clean(&self, cx: &DocContext) -> Item {
         Item {
@@ -2726,6 +2769,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
             visibility: None,
             def_id: self.def_id,
             stability: None,
+            deprecation: None,
         }
     }
 }
@@ -2782,7 +2826,8 @@ impl<'tcx> Clean<Item> 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),
+            deprecation: stability::lookup_deprecation(cx.tcx(), self.def_id).clean(cx),
         }
     }
 }
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 0129ab43cef..d1030a6fcb0 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -40,6 +40,7 @@ pub struct Module {
     pub traits: Vec<Trait>,
     pub vis: hir::Visibility,
     pub stab: Option<attr::Stability>,
+    pub depr: Option<attr::Deprecation>,
     pub impls: Vec<Impl>,
     pub def_traits: Vec<DefaultImpl>,
     pub foreigns: Vec<hir::ForeignMod>,
@@ -54,6 +55,7 @@ impl Module {
             id: 0,
             vis: hir::Inherited,
             stab: None,
+            depr: None,
             where_outer: syntax::codemap::DUMMY_SP,
             where_inner: syntax::codemap::DUMMY_SP,
             attrs      : Vec::new(),
@@ -96,6 +98,7 @@ pub enum TypeBound {
 pub struct Struct {
     pub vis: hir::Visibility,
     pub stab: Option<attr::Stability>,
+    pub depr: Option<attr::Deprecation>,
     pub id: NodeId,
     pub struct_type: StructType,
     pub name: Name,
@@ -108,6 +111,7 @@ pub struct Struct {
 pub struct Enum {
     pub vis: hir::Visibility,
     pub stab: Option<attr::Stability>,
+    pub depr: Option<attr::Deprecation>,
     pub variants: Vec<Variant>,
     pub generics: hir::Generics,
     pub attrs: Vec<ast::Attribute>,
@@ -121,6 +125,7 @@ pub struct Variant {
     pub attrs: Vec<ast::Attribute>,
     pub def: hir::VariantData,
     pub stab: Option<attr::Stability>,
+    pub depr: Option<attr::Deprecation>,
     pub whence: Span,
 }
 
@@ -131,6 +136,7 @@ pub struct Function {
     pub name: Name,
     pub vis: hir::Visibility,
     pub stab: Option<attr::Stability>,
+    pub depr: Option<attr::Deprecation>,
     pub unsafety: hir::Unsafety,
     pub constness: hir::Constness,
     pub whence: Span,
@@ -147,6 +153,7 @@ pub struct Typedef {
     pub whence: Span,
     pub vis: hir::Visibility,
     pub stab: Option<attr::Stability>,
+    pub depr: Option<attr::Deprecation>,
 }
 
 #[derive(Debug)]
@@ -158,6 +165,7 @@ pub struct Static {
     pub attrs: Vec<ast::Attribute>,
     pub vis: hir::Visibility,
     pub stab: Option<attr::Stability>,
+    pub depr: Option<attr::Deprecation>,
     pub id: ast::NodeId,
     pub whence: Span,
 }
@@ -169,6 +177,7 @@ pub struct Constant {
     pub attrs: Vec<ast::Attribute>,
     pub vis: hir::Visibility,
     pub stab: Option<attr::Stability>,
+    pub depr: Option<attr::Deprecation>,
     pub id: ast::NodeId,
     pub whence: Span,
 }
@@ -184,6 +193,7 @@ pub struct Trait {
     pub whence: Span,
     pub vis: hir::Visibility,
     pub stab: Option<attr::Stability>,
+    pub depr: Option<attr::Deprecation>,
 }
 
 pub struct Impl {
@@ -197,6 +207,7 @@ pub struct Impl {
     pub whence: Span,
     pub vis: hir::Visibility,
     pub stab: Option<attr::Stability>,
+    pub depr: Option<attr::Deprecation>,
     pub id: ast::NodeId,
 }
 
@@ -215,6 +226,7 @@ pub struct Macro {
     pub whence: Span,
     pub matchers: Vec<Span>,
     pub stab: Option<attr::Stability>,
+    pub depr: Option<attr::Deprecation>,
     pub imported_from: Option<Name>,
 }
 
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index 0a1860c66f2..5a4f95d1a1a 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -19,7 +19,7 @@ pub trait DocFolder : Sized {
 
     /// don't override!
     fn fold_item_recur(&mut self, item: Item) -> Option<Item> {
-        let Item { attrs, name, source, visibility, def_id, inner, stability } = item;
+        let Item { attrs, name, source, visibility, def_id, inner, stability, deprecation } = item;
         let inner = inner;
         let inner = match inner {
             StructItem(mut i) => {
@@ -66,7 +66,8 @@ pub trait DocFolder : Sized {
         };
 
         Some(Item { attrs: attrs, name: name, source: source, inner: inner,
-                    visibility: visibility, stability: stability, def_id: def_id })
+                    visibility: visibility, stability: stability, deprecation: deprecation,
+                    def_id: def_id })
     }
 
     fn fold_mod(&mut self, m: Module) -> Module {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 45969ed0c64..09a2a1b1c02 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1801,7 +1801,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
 }
 
 fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Option<String> {
-    item.stability.as_ref().and_then(|stab| {
+    let mut result = item.stability.as_ref().and_then(|stab| {
         let reason = if show_reason && !stab.reason.is_empty() {
             format!(": {}", stab.reason)
         } else {
@@ -1836,7 +1836,27 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Optio
         };
         Some(format!("<em class='stab {}'>{}</em>",
                      item.stability_class(), text))
-    })
+    });
+
+    if result.is_none() {
+        result = item.deprecation.as_ref().and_then(|depr| {
+            let note = if show_reason && !depr.note.is_empty() {
+                format!(": {}", depr.note)
+            } else {
+                String::new()
+            };
+            let since = if show_reason && !depr.since.is_empty() {
+                format!(" since {}", Escape(&depr.since))
+            } else {
+                String::new()
+            };
+
+            let text = format!("Deprecated{}{}", since, Markdown(&note));
+            Some(format!("<em class='stab deprecated'>{}</em>", text))
+        });
+    }
+
+    result
 }
 
 struct Initializer<'a>(&'a str);
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 17291233e11..d95a4553bf1 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -64,11 +64,18 @@ impl<'a, 'tcx> RustdocVisitor<'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()
         })
     }
 
+    fn deprecation(&self, id: ast::NodeId) -> Option<attr::Deprecation> {
+        self.cx.tcx_opt().and_then(|tcx| {
+            self.cx.map.opt_local_def_id(id)
+                       .and_then(|def_id| stability::lookup_deprecation(tcx, def_id))
+        })
+    }
+
     pub fn visit(&mut self, krate: &hir::Crate) {
         self.attrs = krate.attrs.clone();
 
@@ -95,6 +102,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             name: name,
             vis: item.vis,
             stab: self.stability(item.id),
+            depr: self.deprecation(item.id),
             attrs: item.attrs.clone(),
             generics: generics.clone(),
             fields: sd.fields().iter().cloned().collect(),
@@ -112,11 +120,13 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 name: v.node.name,
                 attrs: v.node.attrs.clone(),
                 stab: self.stability(v.node.data.id()),
+                depr: self.deprecation(v.node.data.id()),
                 def: v.node.data.clone(),
                 whence: v.span,
             }).collect(),
             vis: it.vis,
             stab: self.stability(it.id),
+            depr: self.deprecation(it.id),
             generics: params.clone(),
             attrs: it.attrs.clone(),
             id: it.id,
@@ -135,6 +145,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             id: item.id,
             vis: item.vis,
             stab: self.stability(item.id),
+            depr: self.deprecation(item.id),
             attrs: item.attrs.clone(),
             decl: fd.clone(),
             name: name,
@@ -156,6 +167,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         om.attrs = attrs;
         om.vis = vis;
         om.stab = self.stability(id);
+        om.depr = self.deprecation(id);
         om.id = id;
         for i in &m.item_ids {
             let item = self.cx.map.expect_item(i.id);
@@ -314,6 +326,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     whence: item.span,
                     vis: item.vis,
                     stab: self.stability(item.id),
+                    depr: self.deprecation(item.id),
                 };
                 om.typedefs.push(t);
             },
@@ -328,6 +341,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     whence: item.span,
                     vis: item.vis,
                     stab: self.stability(item.id),
+                    depr: self.deprecation(item.id),
                 };
                 om.statics.push(s);
             },
@@ -341,6 +355,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     whence: item.span,
                     vis: item.vis,
                     stab: self.stability(item.id),
+                    depr: self.deprecation(item.id),
                 };
                 om.constants.push(s);
             },
@@ -356,6 +371,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     whence: item.span,
                     vis: item.vis,
                     stab: self.stability(item.id),
+                    depr: self.deprecation(item.id),
                 };
                 om.traits.push(t);
             },
@@ -372,6 +388,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     whence: item.span,
                     vis: item.vis,
                     stab: self.stability(item.id),
+                    depr: self.deprecation(item.id),
                 };
                 // Don't duplicate impls when inlining glob imports, we'll pick
                 // them up regardless of where they're located.
@@ -410,6 +427,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             whence: def.span,
             matchers: matchers,
             stab: self.stability(def.id),
+            depr: self.deprecation(def.id),
             imported_from: def.imported_from,
         }
     }
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<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 {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index c456b7dc8b9..f186aff6d36 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<u32>, 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", Normal, Gated("deprecated", "`#[deprecated]` attribute is unstable")),
 
     ("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<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"),
     }
 }
 
diff --git a/src/test/auxiliary/deprecation-lint.rs b/src/test/auxiliary/deprecation-lint.rs
new file mode 100644
index 00000000000..ff872efb7bd
--- /dev/null
+++ b/src/test/auxiliary/deprecation-lint.rs
@@ -0,0 +1,90 @@
+// 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) {}
+}
+
+#[deprecated(since = "1.0.0", note = "text")]
+pub trait DeprecatedTrait { fn dummy(&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/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs
index 09d8302095f..3100aba4b72 100644
--- a/src/test/auxiliary/lint_stability.rs
+++ b/src/test/auxiliary/lint_stability.rs
@@ -100,6 +100,12 @@ pub trait UnstableTrait { fn dummy(&self) { } }
 
 #[stable(feature = "test_feature", since = "1.0.0")]
 #[rustc_deprecated(since = "1.0.0", reason = "text")]
+pub trait DeprecatedTrait {
+    #[stable(feature = "test_feature", since = "1.0.0")] fn dummy(&self) { }
+}
+
+#[stable(feature = "test_feature", since = "1.0.0")]
+#[rustc_deprecated(since = "1.0.0", reason = "text")]
 pub struct DeprecatedStruct {
     #[stable(feature = "test_feature", since = "1.0.0")] pub i: isize
 }
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 <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
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 <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!();
+}
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 <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);
+}
diff --git a/src/test/compile-fail/deprecation-lint.rs b/src/test/compile-fail/deprecation-lint.rs
new file mode 100644
index 00000000000..58fa00fb410
--- /dev/null
+++ b/src/test/compile-fail/deprecation-lint.rs
@@ -0,0 +1,389 @@
+// 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
+    }
+
+    struct S;
+
+    impl DeprecatedTrait for S {} //~ ERROR use of deprecated item: text
+    trait LocalTrait : DeprecatedTrait { } //~ ERROR use of deprecated item: text
+
+    pub fn foo() {
+        let x = Stable {
+            override2: 3,
+            //~^ 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() {}
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 <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() { }
diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs
index f32d7db244b..414d2a857ac 100644
--- a/src/test/compile-fail/lint-stability.rs
+++ b/src/test/compile-fail/lint-stability.rs
@@ -227,8 +227,9 @@ mod cross_crate {
     struct S;
 
     impl UnstableTrait for S { } //~ ERROR use of unstable library feature
-
+    impl DeprecatedTrait for S {} //~ ERROR use of deprecated item: text
     trait LocalTrait : UnstableTrait { } //~ ERROR use of unstable library feature
+    trait LocalTrait2 : DeprecatedTrait { } //~ ERROR use of deprecated item: text
 
     impl Trait for S {
         fn trait_stable(&self) {}
diff --git a/src/test/rustdoc/deprecated.rs b/src/test/rustdoc/deprecated.rs
new file mode 100644
index 00000000000..744304a62c2
--- /dev/null
+++ b/src/test/rustdoc/deprecated.rs
@@ -0,0 +1,16 @@
+// 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)]
+
+// @has deprecated/struct.S.html '//*[@class="stab deprecated"]' \
+//      'Deprecated since 1.0.0: text'
+#[deprecated(since = "1.0.0", note = "text")]
+pub struct S;