]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_passes/stability.rs
Rollup merge of #69623 - Centril:fix-69396-tmp, r=petrochenkov
[rust.git] / src / librustc_passes / stability.rs
index 5c2abb1efa4000ff617ee5e085d6f8a277f1b2a5..f075385ae18b9ac18baf1e8f9cccd58dd3446537 100644 (file)
@@ -9,7 +9,8 @@
 use rustc::session::Session;
 use rustc::ty::query::Providers;
 use rustc::ty::TyCtxt;
-use rustc_attr::{self as attr, Stability};
+use rustc_ast::ast::Attribute;
+use rustc_attr::{self as attr, ConstStability, Stability};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
@@ -20,7 +21,6 @@
 use rustc_infer::traits::misc::can_type_implement_copy;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
-use syntax::ast::Attribute;
 
 use std::cmp::Ordering;
 use std::mem::replace;
@@ -41,6 +41,7 @@ struct Annotator<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     index: &'a mut Index<'tcx>,
     parent_stab: Option<&'tcx Stability>,
+    parent_const_stab: Option<&'tcx ConstStability>,
     parent_depr: Option<DeprecationEntry>,
     in_trait_impl: bool,
 }
@@ -58,144 +59,197 @@ fn annotate<F>(
     ) where
         F: FnOnce(&mut Self),
     {
-        if self.tcx.features().staged_api {
-            // This crate explicitly wants staged API.
-            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 !self.tcx.features().staged_api {
+            self.forbid_staged_api_attrs(hir_id, attrs, item_sp, kind, visit_children);
+            return;
+        }
+
+        // This crate explicitly wants staged API.
+
+        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",
+            );
+        }
+
+        let (stab, const_stab) = attr::find_stability(&self.tcx.sess.parse_sess, attrs, item_sp);
+
+        let const_stab = const_stab.map(|const_stab| {
+            let const_stab = self.tcx.intern_const_stability(const_stab);
+            self.index.const_stab_map.insert(hir_id, const_stab);
+            const_stab
+        });
+
+        if const_stab.is_none() {
+            debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
+            if let Some(parent) = self.parent_const_stab {
+                if parent.level.is_unstable() {
+                    self.index.const_stab_map.insert(hir_id, parent);
+                }
             }
-            let (stab, const_stab) =
-                attr::find_stability(&self.tcx.sess.parse_sess, attrs, item_sp);
-            if let Some(const_stab) = const_stab {
-                let const_stab = self.tcx.intern_const_stability(const_stab);
-                self.index.const_stab_map.insert(hir_id, const_stab);
+        }
+
+        let stab = stab.map(|mut 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())
+            {
+                self.tcx.sess.span_err(item_sp, "This stability annotation is useless");
             }
-            if let Some(mut stab) = 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())
-                {
-                    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
-                    }
+            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)
+            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)
+            {
+                // Explicit version of iter::order::lt to handle parse errors properly
+                for (dep_v, stab_v) in
+                    dep_since.as_str().split('.').zip(stab_since.as_str().split('.'))
                 {
-                    // Explicit version of iter::order::lt to handle parse errors properly
-                    for (dep_v, stab_v) in
-                        dep_since.as_str().split('.').zip(stab_since.as_str().split('.'))
-                    {
-                        if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::<u64>(), stab_v.parse()) {
-                            match dep_v.cmp(&stab_v) {
-                                Ordering::Less => {
-                                    self.tcx.sess.span_err(
-                                        item_sp,
-                                        "An API can't be stabilized \
-                                                                     after it is deprecated",
-                                    );
-                                    break;
-                                }
-                                Ordering::Equal => continue,
-                                Ordering::Greater => break,
+                    if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::<u64>(), stab_v.parse()) {
+                        match dep_v.cmp(&stab_v) {
+                            Ordering::Less => {
+                                self.tcx.sess.span_err(
+                                    item_sp,
+                                    "An API can't be stabilized \
+                                                                 after it is deprecated",
+                                );
+                                break;
                             }
-                        } else {
-                            // Act like it isn't less because the question is now nonsensical,
-                            // and this makes us not do anything else interesting.
-                            self.tcx.sess.span_err(
-                                item_sp,
-                                "Invalid stability or deprecation \
-                                                             version found",
-                            );
-                            break;
+                            Ordering::Equal => continue,
+                            Ordering::Greater => break,
                         }
+                    } else {
+                        // Act like it isn't less because the question is now nonsensical,
+                        // and this makes us not do anything else interesting.
+                        self.tcx.sess.span_err(
+                            item_sp,
+                            "Invalid stability or deprecation \
+                                                         version found",
+                        );
+                        break;
                     }
                 }
-
-                self.index.stab_map.insert(hir_id, stab);
-
-                let orig_parent_stab = replace(&mut self.parent_stab, Some(stab));
-                visit_children(self);
-                self.parent_stab = orig_parent_stab;
-            } else {
-                debug!("annotate: not found, parent = {:?}", self.parent_stab);
-                if let Some(stab) = self.parent_stab {
-                    if stab.level.is_unstable() {
-                        self.index.stab_map.insert(hir_id, stab);
-                    }
-                }
-                visit_children(self);
-            }
-        } else {
-            // Emit errors for non-staged-api crates.
-            let unstable_attrs = [
-                sym::unstable,
-                sym::stable,
-                sym::rustc_deprecated,
-                sym::rustc_const_unstable,
-                sym::rustc_const_stable,
-            ];
-            for attr in attrs {
-                let name = attr.name_or_empty();
-                if unstable_attrs.contains(&name) {
-                    attr::mark_used(attr);
-                    struct_span_err!(
-                        self.tcx.sess,
-                        attr.span,
-                        E0734,
-                        "stability attributes may not be used outside of the standard library",
-                    )
-                    .emit();
-                }
             }
 
-            // Propagate unstability.  This can happen even for non-staged-api crates in case
-            // -Zforce-unstable-if-unmarked is set.
+            self.index.stab_map.insert(hir_id, stab);
+            stab
+        });
+
+        if stab.is_none() {
+            debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
             if let Some(stab) = self.parent_stab {
                 if stab.level.is_unstable() {
                     self.index.stab_map.insert(hir_id, stab);
                 }
             }
+        }
 
-            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");
-                }
+        self.recurse_with_stability_attrs(stab, const_stab, visit_children);
+    }
+
+    fn recurse_with_stability_attrs(
+        &mut self,
+        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_stab = None;
+        let mut replaced_parent_const_stab = None;
+
+        if let Some(stab) = stab {
+            replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
+        }
+        if let Some(const_stab) = const_stab {
+            replaced_parent_const_stab =
+                Some(replace(&mut self.parent_const_stab, Some(const_stab)));
+        }
 
-                // `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);
+        f(self);
+
+        if let Some(orig_parent_stab) = replaced_parent_stab {
+            self.parent_stab = orig_parent_stab;
+        }
+        if let Some(orig_parent_const_stab) = replaced_parent_const_stab {
+            self.parent_const_stab = orig_parent_const_stab;
+        }
+    }
+
+    fn forbid_staged_api_attrs(
+        &mut self,
+        hir_id: HirId,
+        attrs: &[Attribute],
+        item_sp: Span,
+        kind: AnnotationKind,
+        visit_children: impl FnOnce(&mut Self),
+    ) {
+        // Emit errors for non-staged-api crates.
+        let unstable_attrs = [
+            sym::unstable,
+            sym::stable,
+            sym::rustc_deprecated,
+            sym::rustc_const_unstable,
+            sym::rustc_const_stable,
+        ];
+        for attr in attrs {
+            let name = attr.name_or_empty();
+            if unstable_attrs.contains(&name) {
+                attr::mark_used(attr);
+                struct_span_err!(
+                    self.tcx.sess,
+                    attr.span,
+                    E0734,
+                    "stability attributes may not be used outside of the standard library",
+                )
+                .emit();
+            }
+        }
+
+        // Propagate unstability.  This can happen even for non-staged-api crates in case
+        // -Zforce-unstable-if-unmarked is set.
+        if let Some(stab) = self.parent_stab {
+            if stab.level.is_unstable() {
+                self.index.stab_map.insert(hir_id, stab);
             }
         }
+
+        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);
+        }
     }
 }
 
@@ -308,7 +362,7 @@ fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
             // optional. They inherit stability from their parents when unannotated.
             hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod(..) => {}
 
-            _ => self.check_missing_stability(i.hir_id, i.span, i.kind.descriptive_variant()),
+            _ => self.check_missing_stability(i.hir_id, i.span, i.kind.descr()),
         }
 
         intravisit::walk_item(self, i)
@@ -376,6 +430,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
             tcx,
             index: &mut index,
             parent_stab: None,
+            parent_const_stab: None,
             parent_depr: None,
             in_trait_impl: false,
         };
@@ -496,7 +551,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     .emit();
                 } else {
                     let param_env = self.tcx.param_env(def_id);
-                    if !can_type_implement_copy(self.tcx, param_env, ty).is_ok() {
+                    if can_type_implement_copy(self.tcx, param_env, ty).is_err() {
                         feature_err(
                             &self.tcx.sess.parse_sess,
                             sym::untagged_unions,