about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_attr/builtin.rs54
-rw-r--r--src/librustc_middle/middle/stability.rs71
-rw-r--r--src/librustc_passes/stability.rs128
-rw-r--r--src/librustc_resolve/macros.rs19
-rw-r--r--src/librustdoc/clean/mod.rs5
-rw-r--r--src/librustdoc/clean/types.rs13
-rw-r--r--src/librustdoc/html/render.rs29
7 files changed, 138 insertions, 181 deletions
diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs
index 60ceb3e5df9..1e088b52dcc 100644
--- a/src/librustc_attr/builtin.rs
+++ b/src/librustc_attr/builtin.rs
@@ -129,7 +129,6 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
 pub struct Stability {
     pub level: StabilityLevel,
     pub feature: Symbol,
-    pub rustc_depr: Option<RustcDeprecation>,
 }
 
 /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
@@ -162,15 +161,6 @@ impl StabilityLevel {
     }
 }
 
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
-#[derive(HashStable_Generic)]
-pub struct RustcDeprecation {
-    pub since: Symbol,
-    pub reason: Symbol,
-    /// A text snippet used to completely replace any use of the deprecated item in an expression.
-    pub suggestion: Option<Symbol>,
-}
-
 /// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`.
 /// This will not perform any "sanity checks" on the form of the attributes.
 pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool {
@@ -204,7 +194,6 @@ where
     use StabilityLevel::*;
 
     let mut stab: Option<Stability> = None;
-    let mut rustc_depr: Option<RustcDeprecation> = None;
     let mut const_stab: Option<ConstStability> = None;
     let mut promotable = false;
     let mut allow_const_fn_ptr = false;
@@ -256,45 +245,6 @@ where
                 }
             };
 
-            macro_rules! get_meta {
-                ($($name:ident),+) => {
-                    $(
-                        let mut $name = None;
-                    )+
-                    for meta in metas {
-                        if let Some(mi) = meta.meta_item() {
-                            match mi.name_or_empty() {
-                                $(
-                                    sym::$name => if !get(mi, &mut $name) { continue 'outer },
-                                )+
-                                _ => {
-                                    let expected = &[ $( stringify!($name) ),+ ];
-                                    handle_errors(
-                                        sess,
-                                        mi.span,
-                                        AttrError::UnknownMetaItem(
-                                            pprust::path_to_string(&mi.path),
-                                            expected,
-                                        ),
-                                    );
-                                    continue 'outer
-                                }
-                            }
-                        } else {
-                            handle_errors(
-                                sess,
-                                meta.span(),
-                                AttrError::UnsupportedLiteral(
-                                    "unsupported literal",
-                                    false,
-                                ),
-                            );
-                            continue 'outer
-                        }
-                    }
-                }
-            }
-
             let meta_name = meta.name_or_empty();
             match meta_name {
                 sym::rustc_const_unstable | sym::unstable => {
@@ -398,7 +348,7 @@ where
                         (Some(feature), reason, Some(_)) => {
                             let level = Unstable { reason, issue: issue_num, is_soft };
                             if sym::unstable == meta_name {
-                                stab = Some(Stability { level, feature, rustc_depr: None });
+                                stab = Some(Stability { level, feature });
                             } else {
                                 const_stab = Some(ConstStability {
                                     level,
@@ -470,7 +420,7 @@ where
                         (Some(feature), Some(since)) => {
                             let level = Stable { since };
                             if sym::stable == meta_name {
-                                stab = Some(Stability { level, feature, rustc_depr: None });
+                                stab = Some(Stability { level, feature });
                             } else {
                                 const_stab = Some(ConstStability {
                                     level,
diff --git a/src/librustc_middle/middle/stability.rs b/src/librustc_middle/middle/stability.rs
index 54c05bca3bd..5f7ff54fd31 100644
--- a/src/librustc_middle/middle/stability.rs
+++ b/src/librustc_middle/middle/stability.rs
@@ -5,7 +5,7 @@ pub use self::StabilityLevel::*;
 
 use crate::ty::{self, TyCtxt};
 use rustc_ast::ast::CRATE_NODE_ID;
-use rustc_attr::{self as attr, ConstStability, Deprecation, RustcDeprecation, Stability};
+use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_feature::GateIssue;
@@ -130,14 +130,26 @@ pub fn report_unstable(
 
 /// Checks whether an item marked with `deprecated(since="X")` is currently
 /// deprecated (i.e., whether X is not greater than the current rustc version).
-pub fn deprecation_in_effect(since: &str) -> bool {
+pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool {
+    let since = if let Some(since) = since {
+        if is_since_rustc_version {
+            since
+        } else {
+            // We assume that the deprecation is in effect if it's not a
+            // rustc version.
+            return true;
+        }
+    } else {
+        // If since attribute is not set, then we're definitely in effect.
+        return true;
+    };
     fn parse_version(ver: &str) -> Vec<u32> {
         // We ignore non-integer components of the version (e.g., "nightly").
         ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect()
     }
 
     if let Some(rustc) = option_env!("CFG_RELEASE") {
-        let since: Vec<u32> = parse_version(since);
+        let since: Vec<u32> = parse_version(&since);
         let rustc: Vec<u32> = parse_version(rustc);
         // We simply treat invalid `since` attributes as relating to a previous
         // Rust version, thus always displaying the warning.
@@ -167,31 +179,27 @@ pub fn deprecation_suggestion(
     }
 }
 
-fn deprecation_message_common(message: String, reason: Option<Symbol>) -> String {
-    match reason {
-        Some(reason) => format!("{}: {}", message, reason),
-        None => message,
-    }
-}
-
 pub fn deprecation_message(depr: &Deprecation, path: &str) -> (String, &'static Lint) {
-    let message = format!("use of deprecated item '{}'", path);
-    (deprecation_message_common(message, depr.note), DEPRECATED)
-}
-
-pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String, &'static Lint) {
-    let (message, lint) = if deprecation_in_effect(&depr.since.as_str()) {
+    let (message, lint) = if deprecation_in_effect(
+        depr.is_since_rustc_version,
+        depr.since.map(Symbol::as_str).as_deref(),
+    ) {
         (format!("use of deprecated item '{}'", path), DEPRECATED)
     } else {
         (
             format!(
                 "use of item '{}' that will be deprecated in future version {}",
-                path, depr.since
+                path,
+                depr.since.unwrap()
             ),
             DEPRECATED_IN_FUTURE,
         )
     };
-    (deprecation_message_common(message, Some(depr.reason)), lint)
+    let message = match depr.note {
+        Some(reason) => format!("{}: {}", message, reason),
+        None => message,
+    };
+    (message, lint)
 }
 
 pub fn early_report_deprecation(
@@ -289,10 +297,23 @@ impl<'tcx> TyCtxt<'tcx> {
                     .lookup_deprecation_entry(parent_def_id.to_def_id())
                     .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
 
-                if !skip {
+                // #[deprecated] doesn't emit a notice if we're not on the
+                // topmost deprecation. For example, if a struct is deprecated,
+                // the use of a field won't be linted.
+                //
+                // #[rustc_deprecated] however wants to emit down the whole
+                // hierarchy.
+                if !skip || depr_entry.attr.is_since_rustc_version {
                     let (message, lint) =
                         deprecation_message(&depr_entry.attr, &self.def_path_str(def_id));
-                    late_report_deprecation(self, &message, None, lint, span, id);
+                    late_report_deprecation(
+                        self,
+                        &message,
+                        depr_entry.attr.suggestion,
+                        lint,
+                        span,
+                        id,
+                    );
                 }
             };
         }
@@ -310,16 +331,6 @@ impl<'tcx> TyCtxt<'tcx> {
             def_id, span, stability
         );
 
-        if let Some(id) = id {
-            if let Some(stability) = stability {
-                if let Some(depr) = &stability.rustc_depr {
-                    let (message, lint) =
-                        rustc_deprecation_message(depr, &self.def_path_str(def_id));
-                    late_report_deprecation(self, &message, depr.suggestion, lint, span, id);
-                }
-            }
-        }
-
         // Only the cross-crate scenario matters when checking unstable APIs
         let cross_crate = !def_id.is_local();
         if !cross_crate {
diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs
index 5d972c70d13..830af8d31e7 100644
--- a/src/librustc_passes/stability.rs
+++ b/src/librustc_passes/stability.rs
@@ -59,20 +59,50 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
     ) where
         F: FnOnce(&mut Self),
     {
+        debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
+        let mut did_error = false;
         if !self.tcx.features().staged_api {
-            self.forbid_staged_api_attrs(hir_id, attrs, item_sp, kind, visit_children);
-            return;
+            did_error = self.forbid_staged_api_attrs(hir_id, attrs);
         }
 
-        // This crate explicitly wants staged API.
+        let depr = if did_error {
+            None
+        } else {
+            attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp)
+        };
+        let mut is_deprecated = false;
+        if let Some(depr) = &depr {
+            is_deprecated = true;
 
-        debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
-        if let Some(..) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) {
-            self.tcx.sess.span_err(
-                item_sp,
-                "`#[deprecated]` cannot be used in staged API; \
-                                             use `#[rustc_deprecated]` instead",
+            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 depr_entry = DeprecationEntry::local(depr.clone(), hir_id);
+            self.index.depr_map.insert(hir_id, depr_entry);
+        } else if let Some(parent_depr) = self.parent_depr.clone() {
+            is_deprecated = true;
+            info!("tagging child {:?} as deprecated from parent", hir_id);
+            self.index.depr_map.insert(hir_id, parent_depr);
+        }
+
+        if self.tcx.features().staged_api {
+            if let Some(..) = attrs.iter().find(|a| a.check_name(sym::deprecated)) {
+                self.tcx.sess.span_err(
+                    item_sp,
+                    "`#[deprecated]` cannot be used in staged API; \
+                                                use `#[rustc_deprecated]` instead",
+                );
+            }
+        } else {
+            self.recurse_with_stability_attrs(
+                depr.map(|d| DeprecationEntry::local(d, hir_id)),
+                None,
+                None,
+                visit_children,
             );
+            return;
         }
 
         let (stab, const_stab) = attr::find_stability(&self.tcx.sess.parse_sess, attrs, item_sp);
@@ -92,33 +122,34 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             }
         }
 
-        let stab = stab.map(|mut stab| {
+        if depr.as_ref().map_or(false, |d| d.is_since_rustc_version) {
+            if stab.is_none() {
+                struct_span_err!(
+                    self.tcx.sess,
+                    item_sp,
+                    E0549,
+                    "rustc_deprecated attribute must be paired with \
+                    either stable or unstable attribute"
+                )
+                .emit();
+            }
+        }
+
+        let stab = stab.map(|stab| {
             // Error if prohibited, or can't inherit anything from a container.
             if kind == AnnotationKind::Prohibited
-                || (kind == AnnotationKind::Container
-                    && stab.level.is_stable()
-                    && stab.rustc_depr.is_none())
+                || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
             {
                 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_stab {
-                if parent_stab.rustc_depr.is_some() && stab.rustc_depr.is_none() {
-                    stab.rustc_depr = parent_stab.rustc_depr
-                }
-            }
-
             let stab = self.tcx.intern_stability(stab);
 
             // Check if deprecated_since < stable_since. If it is,
             // this is *almost surely* an accident.
-            if let (
-                &Some(attr::RustcDeprecation { since: dep_since, .. }),
-                &attr::Stable { since: stab_since },
-            ) = (&stab.rustc_depr, &stab.level)
+            if let (&Some(dep_since), &attr::Stable { since: stab_since }) =
+                (&depr.as_ref().and_then(|d| d.since), &stab.level)
             {
                 // Explicit version of iter::order::lt to handle parse errors properly
                 for (dep_v, stab_v) in
@@ -163,19 +194,29 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             }
         }
 
-        self.recurse_with_stability_attrs(stab, const_stab, visit_children);
+        self.recurse_with_stability_attrs(
+            depr.map(|d| DeprecationEntry::local(d, hir_id)),
+            stab,
+            const_stab,
+            visit_children,
+        );
     }
 
     fn recurse_with_stability_attrs(
         &mut self,
+        depr: Option<DeprecationEntry>,
         stab: Option<&'tcx Stability>,
         const_stab: Option<&'tcx ConstStability>,
         f: impl FnOnce(&mut Self),
     ) {
         // These will be `Some` if this item changes the corresponding stability attribute.
+        let mut replaced_parent_depr = None;
         let mut replaced_parent_stab = None;
         let mut replaced_parent_const_stab = None;
 
+        if let Some(depr) = depr {
+            replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
+        }
         if let Some(stab) = stab {
             replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
         }
@@ -186,6 +227,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
 
         f(self);
 
+        if let Some(orig_parent_depr) = replaced_parent_depr {
+            self.parent_depr = orig_parent_depr;
+        }
         if let Some(orig_parent_stab) = replaced_parent_stab {
             self.parent_stab = orig_parent_stab;
         }
@@ -194,14 +238,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         }
     }
 
-    fn forbid_staged_api_attrs(
-        &mut self,
-        hir_id: HirId,
-        attrs: &[Attribute],
-        item_sp: Span,
-        kind: AnnotationKind,
-        visit_children: impl FnOnce(&mut Self),
-    ) {
+    // returns true if an error occurred, used to suppress some spurious errors
+    fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool {
         // Emit errors for non-staged-api crates.
         let unstable_attrs = [
             sym::unstable,
@@ -210,6 +248,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             sym::rustc_const_unstable,
             sym::rustc_const_stable,
         ];
+        let mut has_error = false;
         for attr in attrs {
             let name = attr.name_or_empty();
             if unstable_attrs.contains(&name) {
@@ -221,6 +260,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                     "stability attributes may not be used outside of the standard library",
                 )
                 .emit();
+                has_error = true;
             }
         }
 
@@ -232,24 +272,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             }
         }
 
-        if let Some(depr) = attr::find_deprecation(&self.tcx.sess.parse_sess, 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 depr_entry = DeprecationEntry::local(depr, hir_id);
-            self.index.depr_map.insert(hir_id, depr_entry.clone());
-
-            let orig_parent_depr = replace(&mut self.parent_depr, Some(depr_entry));
-            visit_children(self);
-            self.parent_depr = orig_parent_depr;
-        } else if let Some(parent_depr) = self.parent_depr.clone() {
-            self.index.depr_map.insert(hir_id, parent_depr);
-            visit_children(self);
-        } else {
-            visit_children(self);
-        }
+        has_error
     }
 }
 
@@ -454,7 +477,6 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
                     is_soft: false,
                 },
                 feature: sym::rustc_private,
-                rustc_depr: None,
             });
             annotator.parent_stab = Some(stability);
         }
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 3976e501c16..fee7cb4836e 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -1017,22 +1017,17 @@ impl<'a> Resolver<'a> {
                     );
                 }
             }
-            if let Some(depr) = &stability.rustc_depr {
-                let path = pprust::path_to_string(path);
-                let (message, lint) = stability::rustc_deprecation_message(depr, &path);
-                stability::early_report_deprecation(
-                    &mut self.lint_buffer,
-                    &message,
-                    depr.suggestion,
-                    lint,
-                    span,
-                );
-            }
         }
         if let Some(depr) = &ext.deprecation {
             let path = pprust::path_to_string(&path);
             let (message, lint) = stability::deprecation_message(depr, &path);
-            stability::early_report_deprecation(&mut self.lint_buffer, &message, None, lint, span);
+            stability::early_report_deprecation(
+                &mut self.lint_buffer,
+                &message,
+                depr.suggestion,
+                lint,
+                span,
+            );
         }
     }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 8a4ee91df40..94d95115dcd 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2353,10 +2353,6 @@ impl Clean<Stability> for attr::Stability {
                 attr::Stable { ref since } => since.to_string(),
                 _ => String::new(),
             },
-            deprecation: self.rustc_depr.as_ref().map(|d| Deprecation {
-                note: Some(d.reason.to_string()).filter(|r| !r.is_empty()),
-                since: Some(d.since.to_string()).filter(|d| !d.is_empty()),
-            }),
             unstable_reason: match self.level {
                 attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()),
                 _ => None,
@@ -2374,6 +2370,7 @@ impl Clean<Deprecation> for attr::Deprecation {
         Deprecation {
             since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()),
             note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()),
+            is_since_rustc_version: self.is_since_rustc_version,
         }
     }
 }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 6a03722cd08..071834c59d6 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -195,7 +195,8 @@ impl Item {
                 classes.push("unstable");
             }
 
-            if s.deprecation.is_some() {
+            // FIXME: what about non-staged API items that are deprecated?
+            if self.deprecation.is_some() {
                 classes.push("deprecated");
             }
 
@@ -216,14 +217,6 @@ impl Item {
         ItemType::from(self)
     }
 
-    /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
-    ///
-    /// If the item is not deprecated, returns `None`.
-    pub fn deprecation(&self) -> Option<&Deprecation> {
-        self.deprecation
-            .as_ref()
-            .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
-    }
     pub fn is_default(&self) -> bool {
         match self.inner {
             ItemEnum::MethodItem(ref meth) => {
@@ -1528,7 +1521,6 @@ pub struct Stability {
     pub level: stability::StabilityLevel,
     pub feature: Option<String>,
     pub since: String,
-    pub deprecation: Option<Deprecation>,
     pub unstable_reason: Option<String>,
     pub issue: Option<NonZeroU32>,
 }
@@ -1537,6 +1529,7 @@ pub struct Stability {
 pub struct Deprecation {
     pub since: Option<String>,
     pub note: Option<String>,
+    pub is_since_rustc_version: bool,
 }
 
 /// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index f872ed7010c..f7050cf3777 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2216,16 +2216,10 @@ fn stability_tags(item: &clean::Item) -> String {
     }
 
     // The trailing space after each tag is to space it properly against the rest of the docs.
-    if item.deprecation().is_some() {
+    if let Some(depr) = &item.deprecation {
         let mut message = "Deprecated";
-        if let Some(ref stab) = item.stability {
-            if let Some(ref depr) = stab.deprecation {
-                if let Some(ref since) = depr.since {
-                    if !stability::deprecation_in_effect(&since) {
-                        message = "Deprecation planned";
-                    }
-                }
-            }
+        if !stability::deprecation_in_effect(depr.is_since_rustc_version, depr.since.as_deref()) {
+            message = "Deprecation planned";
         }
         tags += &tag_html("deprecated", message);
     }
@@ -2254,23 +2248,18 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
     let mut stability = vec![];
     let error_codes = cx.shared.codes;
 
-    if let Some(Deprecation { note, since }) = &item.deprecation() {
+    if let Some(Deprecation { ref note, ref since, is_since_rustc_version }) = item.deprecation {
         // We display deprecation messages for #[deprecated] and #[rustc_deprecated]
         // but only display the future-deprecation messages for #[rustc_deprecated].
         let mut message = if let Some(since) = since {
-            format!("Deprecated since {}", Escape(since))
+            if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) {
+                format!("Deprecating in {}", Escape(&since))
+            } else {
+                format!("Deprecated since {}", Escape(&since))
+            }
         } else {
             String::from("Deprecated")
         };
-        if let Some(ref stab) = item.stability {
-            if let Some(ref depr) = stab.deprecation {
-                if let Some(ref since) = depr.since {
-                    if !stability::deprecation_in_effect(&since) {
-                        message = format!("Deprecating in {}", Escape(&since));
-                    }
-                }
-            }
-        }
 
         if let Some(note) = note {
             let mut ids = cx.id_map.borrow_mut();