]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_passes/src/stability.rs
Rollup merge of #78086 - poliorcetics:as-placeholder, r=Mark-Simulacrum
[rust.git] / compiler / rustc_passes / src / stability.rs
1 //! A pass that annotates every item and method with its stability level,
2 //! propagating default levels lexically from parent to children ast nodes.
3
4 use rustc_ast::Attribute;
5 use rustc_attr::{self as attr, ConstStability, Stability};
6 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
7 use rustc_errors::struct_span_err;
8 use rustc_hir as hir;
9 use rustc_hir::def::{DefKind, Res};
10 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
11 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
12 use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Variant};
13 use rustc_middle::hir::map::Map;
14 use rustc_middle::middle::privacy::AccessLevels;
15 use rustc_middle::middle::stability::{DeprecationEntry, Index};
16 use rustc_middle::ty::{self, query::Providers, TyCtxt};
17 use rustc_session::lint;
18 use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
19 use rustc_session::parse::feature_err;
20 use rustc_session::Session;
21 use rustc_span::symbol::{sym, Symbol};
22 use rustc_span::{Span, DUMMY_SP};
23
24 use std::cmp::Ordering;
25 use std::mem::replace;
26 use std::num::NonZeroU32;
27
28 #[derive(PartialEq)]
29 enum AnnotationKind {
30     // Annotation is required if not inherited from unstable parents
31     Required,
32     // Annotation is useless, reject it
33     Prohibited,
34     // Deprecation annotation is useless, reject it. (Stability attribute is still required.)
35     DeprecationProhibited,
36     // Annotation itself is useless, but it can be propagated to children
37     Container,
38 }
39
40 /// Whether to inherit deprecation flags for nested items. In most cases, we do want to inherit
41 /// deprecation, because nested items rarely have individual deprecation attributes, and so
42 /// should be treated as deprecated if their parent is. However, default generic parameters
43 /// have separate deprecation attributes from their parents, so we do not wish to inherit
44 /// deprecation in this case. For example, inheriting deprecation for `T` in `Foo<T>`
45 /// would cause a duplicate warning arising from both `Foo` and `T` being deprecated.
46 #[derive(Clone)]
47 enum InheritDeprecation {
48     Yes,
49     No,
50 }
51
52 impl InheritDeprecation {
53     fn yes(&self) -> bool {
54         matches!(self, InheritDeprecation::Yes)
55     }
56 }
57
58 // A private tree-walker for producing an Index.
59 struct Annotator<'a, 'tcx> {
60     tcx: TyCtxt<'tcx>,
61     index: &'a mut Index<'tcx>,
62     parent_stab: Option<&'tcx Stability>,
63     parent_const_stab: Option<&'tcx ConstStability>,
64     parent_depr: Option<DeprecationEntry>,
65     in_trait_impl: bool,
66 }
67
68 impl<'a, 'tcx> Annotator<'a, 'tcx> {
69     // Determine the stability for a node based on its attributes and inherited
70     // stability. The stability is recorded in the index and used as the parent.
71     fn annotate<F>(
72         &mut self,
73         hir_id: HirId,
74         attrs: &[Attribute],
75         item_sp: Span,
76         kind: AnnotationKind,
77         inherit_deprecation: InheritDeprecation,
78         visit_children: F,
79     ) where
80         F: FnOnce(&mut Self),
81     {
82         debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
83         let mut did_error = false;
84         if !self.tcx.features().staged_api {
85             did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation.clone());
86         }
87
88         let depr = if did_error { None } else { attr::find_deprecation(&self.tcx.sess, attrs) };
89         let mut is_deprecated = false;
90         if let Some((depr, span)) = &depr {
91             is_deprecated = true;
92
93             if kind == AnnotationKind::Prohibited || kind == AnnotationKind::DeprecationProhibited {
94                 self.tcx.struct_span_lint_hir(USELESS_DEPRECATED, hir_id, *span, |lint| {
95                     lint.build("this `#[deprecated]` annotation has no effect")
96                         .span_suggestion_short(
97                             *span,
98                             "remove the unnecessary deprecation attribute",
99                             String::new(),
100                             rustc_errors::Applicability::MachineApplicable,
101                         )
102                         .emit()
103                 });
104             }
105
106             // `Deprecation` is just two pointers, no need to intern it
107             let depr_entry = DeprecationEntry::local(depr.clone(), hir_id);
108             self.index.depr_map.insert(hir_id, depr_entry);
109         } else if let Some(parent_depr) = self.parent_depr.clone() {
110             if inherit_deprecation.yes() {
111                 is_deprecated = true;
112                 info!("tagging child {:?} as deprecated from parent", hir_id);
113                 self.index.depr_map.insert(hir_id, parent_depr);
114             }
115         }
116
117         if self.tcx.features().staged_api {
118             if let Some(..) = attrs.iter().find(|a| self.tcx.sess.check_name(a, sym::deprecated)) {
119                 self.tcx.sess.span_err(
120                     item_sp,
121                     "`#[deprecated]` cannot be used in staged API; \
122                                                 use `#[rustc_deprecated]` instead",
123                 );
124             }
125         } else {
126             self.recurse_with_stability_attrs(
127                 depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)),
128                 None,
129                 None,
130                 visit_children,
131             );
132             return;
133         }
134
135         let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
136
137         let const_stab = const_stab.map(|const_stab| {
138             let const_stab = self.tcx.intern_const_stability(const_stab);
139             self.index.const_stab_map.insert(hir_id, const_stab);
140             const_stab
141         });
142
143         if const_stab.is_none() {
144             debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
145             if let Some(parent) = self.parent_const_stab {
146                 if parent.level.is_unstable() {
147                     self.index.const_stab_map.insert(hir_id, parent);
148                 }
149             }
150         }
151
152         if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr {
153             if stab.is_none() {
154                 struct_span_err!(
155                     self.tcx.sess,
156                     *span,
157                     E0549,
158                     "rustc_deprecated attribute must be paired with \
159                     either stable or unstable attribute"
160                 )
161                 .emit();
162             }
163         }
164
165         let stab = stab.map(|stab| {
166             // Error if prohibited, or can't inherit anything from a container.
167             if kind == AnnotationKind::Prohibited
168                 || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
169             {
170                 self.tcx.sess.span_err(item_sp, "This stability annotation is useless");
171             }
172
173             debug!("annotate: found {:?}", stab);
174             let stab = self.tcx.intern_stability(stab);
175
176             // Check if deprecated_since < stable_since. If it is,
177             // this is *almost surely* an accident.
178             if let (&Some(dep_since), &attr::Stable { since: stab_since }) =
179                 (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level)
180             {
181                 // Explicit version of iter::order::lt to handle parse errors properly
182                 for (dep_v, stab_v) in
183                     dep_since.as_str().split('.').zip(stab_since.as_str().split('.'))
184                 {
185                     if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::<u64>(), stab_v.parse()) {
186                         match dep_v.cmp(&stab_v) {
187                             Ordering::Less => {
188                                 self.tcx.sess.span_err(
189                                     item_sp,
190                                     "An API can't be stabilized \
191                                                                  after it is deprecated",
192                                 );
193                                 break;
194                             }
195                             Ordering::Equal => continue,
196                             Ordering::Greater => break,
197                         }
198                     } else {
199                         // Act like it isn't less because the question is now nonsensical,
200                         // and this makes us not do anything else interesting.
201                         self.tcx.sess.span_err(
202                             item_sp,
203                             "Invalid stability or deprecation \
204                                                          version found",
205                         );
206                         break;
207                     }
208                 }
209             }
210
211             self.index.stab_map.insert(hir_id, stab);
212             stab
213         });
214
215         if stab.is_none() {
216             debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
217             if let Some(stab) = self.parent_stab {
218                 if inherit_deprecation.yes() && stab.level.is_unstable() {
219                     self.index.stab_map.insert(hir_id, stab);
220                 }
221             }
222         }
223
224         self.recurse_with_stability_attrs(
225             depr.map(|(d, _)| DeprecationEntry::local(d, hir_id)),
226             stab,
227             const_stab,
228             visit_children,
229         );
230     }
231
232     fn recurse_with_stability_attrs(
233         &mut self,
234         depr: Option<DeprecationEntry>,
235         stab: Option<&'tcx Stability>,
236         const_stab: Option<&'tcx ConstStability>,
237         f: impl FnOnce(&mut Self),
238     ) {
239         // These will be `Some` if this item changes the corresponding stability attribute.
240         let mut replaced_parent_depr = None;
241         let mut replaced_parent_stab = None;
242         let mut replaced_parent_const_stab = None;
243
244         if let Some(depr) = depr {
245             replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
246         }
247         if let Some(stab) = stab {
248             replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
249         }
250         if let Some(const_stab) = const_stab {
251             replaced_parent_const_stab =
252                 Some(replace(&mut self.parent_const_stab, Some(const_stab)));
253         }
254
255         f(self);
256
257         if let Some(orig_parent_depr) = replaced_parent_depr {
258             self.parent_depr = orig_parent_depr;
259         }
260         if let Some(orig_parent_stab) = replaced_parent_stab {
261             self.parent_stab = orig_parent_stab;
262         }
263         if let Some(orig_parent_const_stab) = replaced_parent_const_stab {
264             self.parent_const_stab = orig_parent_const_stab;
265         }
266     }
267
268     // returns true if an error occurred, used to suppress some spurious errors
269     fn forbid_staged_api_attrs(
270         &mut self,
271         hir_id: HirId,
272         attrs: &[Attribute],
273         inherit_deprecation: InheritDeprecation,
274     ) -> bool {
275         // Emit errors for non-staged-api crates.
276         let unstable_attrs = [
277             sym::unstable,
278             sym::stable,
279             sym::rustc_deprecated,
280             sym::rustc_const_unstable,
281             sym::rustc_const_stable,
282         ];
283         let mut has_error = false;
284         for attr in attrs {
285             let name = attr.name_or_empty();
286             if unstable_attrs.contains(&name) {
287                 self.tcx.sess.mark_attr_used(attr);
288                 struct_span_err!(
289                     self.tcx.sess,
290                     attr.span,
291                     E0734,
292                     "stability attributes may not be used outside of the standard library",
293                 )
294                 .emit();
295                 has_error = true;
296             }
297         }
298
299         // Propagate unstability.  This can happen even for non-staged-api crates in case
300         // -Zforce-unstable-if-unmarked is set.
301         if let Some(stab) = self.parent_stab {
302             if inherit_deprecation.yes() && stab.level.is_unstable() {
303                 self.index.stab_map.insert(hir_id, stab);
304             }
305         }
306
307         has_error
308     }
309 }
310
311 impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
312     /// Because stability levels are scoped lexically, we want to walk
313     /// nested items in the context of the outer item, so enable
314     /// deep-walking.
315     type Map = Map<'tcx>;
316
317     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
318         NestedVisitorMap::All(self.tcx.hir())
319     }
320
321     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
322         let orig_in_trait_impl = self.in_trait_impl;
323         let mut kind = AnnotationKind::Required;
324         match i.kind {
325             // Inherent impls and foreign modules serve only as containers for other items,
326             // they don't have their own stability. They still can be annotated as unstable
327             // and propagate this unstability to children, but this annotation is completely
328             // optional. They inherit stability from their parents when unannotated.
329             hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod { .. } => {
330                 self.in_trait_impl = false;
331                 kind = AnnotationKind::Container;
332             }
333             hir::ItemKind::Impl { of_trait: Some(_), .. } => {
334                 self.in_trait_impl = true;
335                 kind = AnnotationKind::DeprecationProhibited;
336             }
337             hir::ItemKind::Struct(ref sd, _) => {
338                 if let Some(ctor_hir_id) = sd.ctor_hir_id() {
339                     self.annotate(
340                         ctor_hir_id,
341                         &i.attrs,
342                         i.span,
343                         AnnotationKind::Required,
344                         InheritDeprecation::Yes,
345                         |_| {},
346                     )
347                 }
348             }
349             _ => {}
350         }
351
352         self.annotate(i.hir_id, &i.attrs, i.span, kind, InheritDeprecation::Yes, |v| {
353             intravisit::walk_item(v, i)
354         });
355         self.in_trait_impl = orig_in_trait_impl;
356     }
357
358     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
359         self.annotate(
360             ti.hir_id,
361             &ti.attrs,
362             ti.span,
363             AnnotationKind::Required,
364             InheritDeprecation::Yes,
365             |v| {
366                 intravisit::walk_trait_item(v, ti);
367             },
368         );
369     }
370
371     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
372         let kind =
373             if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
374         self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, InheritDeprecation::Yes, |v| {
375             intravisit::walk_impl_item(v, ii);
376         });
377     }
378
379     fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
380         self.annotate(
381             var.id,
382             &var.attrs,
383             var.span,
384             AnnotationKind::Required,
385             InheritDeprecation::Yes,
386             |v| {
387                 if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
388                     v.annotate(
389                         ctor_hir_id,
390                         &var.attrs,
391                         var.span,
392                         AnnotationKind::Required,
393                         InheritDeprecation::Yes,
394                         |_| {},
395                     );
396                 }
397
398                 intravisit::walk_variant(v, var, g, item_id)
399             },
400         )
401     }
402
403     fn visit_struct_field(&mut self, s: &'tcx StructField<'tcx>) {
404         self.annotate(
405             s.hir_id,
406             &s.attrs,
407             s.span,
408             AnnotationKind::Required,
409             InheritDeprecation::Yes,
410             |v| {
411                 intravisit::walk_struct_field(v, s);
412             },
413         );
414     }
415
416     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
417         self.annotate(
418             i.hir_id,
419             &i.attrs,
420             i.span,
421             AnnotationKind::Required,
422             InheritDeprecation::Yes,
423             |v| {
424                 intravisit::walk_foreign_item(v, i);
425             },
426         );
427     }
428
429     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
430         self.annotate(
431             md.hir_id,
432             &md.attrs,
433             md.span,
434             AnnotationKind::Required,
435             InheritDeprecation::Yes,
436             |_| {},
437         );
438     }
439
440     fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
441         let kind = match &p.kind {
442             // FIXME(const_generics:defaults)
443             hir::GenericParamKind::Type { default, .. } if default.is_some() => {
444                 AnnotationKind::Container
445             }
446             _ => AnnotationKind::Prohibited,
447         };
448
449         self.annotate(p.hir_id, &p.attrs, p.span, kind, InheritDeprecation::No, |v| {
450             intravisit::walk_generic_param(v, p);
451         });
452     }
453 }
454
455 struct MissingStabilityAnnotations<'tcx> {
456     tcx: TyCtxt<'tcx>,
457     access_levels: &'tcx AccessLevels,
458 }
459
460 impl<'tcx> MissingStabilityAnnotations<'tcx> {
461     fn check_missing_stability(&self, hir_id: HirId, span: Span) {
462         let stab = self.tcx.stability().local_stability(hir_id);
463         let is_error =
464             !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(hir_id);
465         if is_error {
466             let def_id = self.tcx.hir().local_def_id(hir_id);
467             let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
468             self.tcx.sess.span_err(span, &format!("{} has missing stability attribute", descr));
469         }
470     }
471
472     fn check_missing_const_stability(&self, hir_id: HirId, span: Span) {
473         let stab_map = self.tcx.stability();
474         let stab = stab_map.local_stability(hir_id);
475         if stab.map_or(false, |stab| stab.level.is_stable()) {
476             let const_stab = stab_map.local_const_stability(hir_id);
477             if const_stab.is_none() {
478                 self.tcx.sess.span_err(
479                     span,
480                     "`#[stable]` const functions must also be either \
481                     `#[rustc_const_stable]` or `#[rustc_const_unstable]`",
482                 );
483             }
484         }
485     }
486 }
487
488 impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
489     type Map = Map<'tcx>;
490
491     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
492         NestedVisitorMap::OnlyBodies(self.tcx.hir())
493     }
494
495     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
496         // Inherent impls and foreign modules serve only as containers for other items,
497         // they don't have their own stability. They still can be annotated as unstable
498         // and propagate this unstability to children, but this annotation is completely
499         // optional. They inherit stability from their parents when unannotated.
500         if !matches!(
501             i.kind,
502             hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod { .. }
503         ) {
504             self.check_missing_stability(i.hir_id, i.span);
505         }
506
507         // Ensure `const fn` that are `stable` have one of `rustc_const_unstable` or
508         // `rustc_const_stable`.
509         if self.tcx.features().staged_api
510             && matches!(&i.kind, hir::ItemKind::Fn(sig, ..) if sig.header.is_const())
511         {
512             self.check_missing_const_stability(i.hir_id, i.span);
513         }
514
515         intravisit::walk_item(self, i)
516     }
517
518     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
519         self.check_missing_stability(ti.hir_id, ti.span);
520         intravisit::walk_trait_item(self, ti);
521     }
522
523     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
524         let impl_def_id = self.tcx.hir().local_def_id(self.tcx.hir().get_parent_item(ii.hir_id));
525         if self.tcx.impl_trait_ref(impl_def_id).is_none() {
526             self.check_missing_stability(ii.hir_id, ii.span);
527         }
528         intravisit::walk_impl_item(self, ii);
529     }
530
531     fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
532         self.check_missing_stability(var.id, var.span);
533         intravisit::walk_variant(self, var, g, item_id);
534     }
535
536     fn visit_struct_field(&mut self, s: &'tcx StructField<'tcx>) {
537         self.check_missing_stability(s.hir_id, s.span);
538         intravisit::walk_struct_field(self, s);
539     }
540
541     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
542         self.check_missing_stability(i.hir_id, i.span);
543         intravisit::walk_foreign_item(self, i);
544     }
545
546     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
547         self.check_missing_stability(md.hir_id, md.span);
548     }
549
550     // Note that we don't need to `check_missing_stability` for default generic parameters,
551     // as we assume that any default generic parameters without attributes are automatically
552     // stable (assuming they have not inherited instability from their parent).
553 }
554
555 fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> {
556     let is_staged_api =
557         tcx.sess.opts.debugging_opts.force_unstable_if_unmarked || tcx.features().staged_api;
558     let mut staged_api = FxHashMap::default();
559     staged_api.insert(LOCAL_CRATE, is_staged_api);
560     let mut index = Index {
561         staged_api,
562         stab_map: Default::default(),
563         const_stab_map: Default::default(),
564         depr_map: Default::default(),
565         active_features: Default::default(),
566     };
567
568     let active_lib_features = &tcx.features().declared_lib_features;
569     let active_lang_features = &tcx.features().declared_lang_features;
570
571     // Put the active features into a map for quick lookup.
572     index.active_features = active_lib_features
573         .iter()
574         .map(|&(s, ..)| s)
575         .chain(active_lang_features.iter().map(|&(s, ..)| s))
576         .collect();
577
578     {
579         let krate = tcx.hir().krate();
580         let mut annotator = Annotator {
581             tcx,
582             index: &mut index,
583             parent_stab: None,
584             parent_const_stab: None,
585             parent_depr: None,
586             in_trait_impl: false,
587         };
588
589         // If the `-Z force-unstable-if-unmarked` flag is passed then we provide
590         // a parent stability annotation which indicates that this is private
591         // with the `rustc_private` feature. This is intended for use when
592         // compiling `librustc_*` crates themselves so we can leverage crates.io
593         // while maintaining the invariant that all sysroot crates are unstable
594         // by default and are unable to be used.
595         if tcx.sess.opts.debugging_opts.force_unstable_if_unmarked {
596             let reason = "this crate is being loaded from the sysroot, an \
597                           unstable location; did you mean to load this crate \
598                           from crates.io via `Cargo.toml` instead?";
599             let stability = tcx.intern_stability(Stability {
600                 level: attr::StabilityLevel::Unstable {
601                     reason: Some(Symbol::intern(reason)),
602                     issue: NonZeroU32::new(27812),
603                     is_soft: false,
604                 },
605                 feature: sym::rustc_private,
606             });
607             annotator.parent_stab = Some(stability);
608         }
609
610         annotator.annotate(
611             hir::CRATE_HIR_ID,
612             &krate.item.attrs,
613             krate.item.span,
614             AnnotationKind::Required,
615             InheritDeprecation::Yes,
616             |v| intravisit::walk_crate(v, krate),
617         );
618     }
619     index
620 }
621
622 /// Cross-references the feature names of unstable APIs with enabled
623 /// features and possibly prints errors.
624 fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
625     tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx }.as_deep_visitor());
626 }
627
628 pub(crate) fn provide(providers: &mut Providers) {
629     *providers = Providers { check_mod_unstable_api_usage, ..*providers };
630     providers.stability_index = |tcx, cnum| {
631         assert_eq!(cnum, LOCAL_CRATE);
632         new_index(tcx)
633     };
634 }
635
636 struct Checker<'tcx> {
637     tcx: TyCtxt<'tcx>,
638 }
639
640 impl Visitor<'tcx> for Checker<'tcx> {
641     type Map = Map<'tcx>;
642
643     /// Because stability levels are scoped lexically, we want to walk
644     /// nested items in the context of the outer item, so enable
645     /// deep-walking.
646     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
647         NestedVisitorMap::OnlyBodies(self.tcx.hir())
648     }
649
650     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
651         match item.kind {
652             hir::ItemKind::ExternCrate(_) => {
653                 // compiler-generated `extern crate` items have a dummy span.
654                 // `std` is still checked for the `restricted-std` feature.
655                 if item.span.is_dummy() && item.ident.as_str() != "std" {
656                     return;
657                 }
658
659                 let def_id = self.tcx.hir().local_def_id(item.hir_id);
660                 let cnum = match self.tcx.extern_mod_stmt_cnum(def_id) {
661                     Some(cnum) => cnum,
662                     None => return,
663                 };
664                 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
665                 self.tcx.check_stability(def_id, Some(item.hir_id), item.span);
666             }
667
668             // For implementations of traits, check the stability of each item
669             // individually as it's possible to have a stable trait with unstable
670             // items.
671             hir::ItemKind::Impl { of_trait: Some(ref t), self_ty, items, .. } => {
672                 if self.tcx.features().staged_api {
673                     // If this impl block has an #[unstable] attribute, give an
674                     // error if all involved types and traits are stable, because
675                     // it will have no effect.
676                     // See: https://github.com/rust-lang/rust/issues/55436
677                     if let (Some(Stability { level: attr::Unstable { .. }, .. }), _) =
678                         attr::find_stability(&self.tcx.sess, &item.attrs, item.span)
679                     {
680                         let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
681                         c.visit_ty(self_ty);
682                         c.visit_trait_ref(t);
683                         if c.fully_stable {
684                             let span = item
685                                 .attrs
686                                 .iter()
687                                 .find(|a| a.has_name(sym::unstable))
688                                 .map_or(item.span, |a| a.span);
689                             self.tcx.struct_span_lint_hir(
690                                 INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
691                                 item.hir_id,
692                                 span,
693                                 |lint| lint
694                                     .build("an `#[unstable]` annotation here has no effect")
695                                     .note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
696                                     .emit()
697                             );
698                         }
699                     }
700                 }
701
702                 if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
703                     for impl_item_ref in items {
704                         let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
705                         let trait_item_def_id = self
706                             .tcx
707                             .associated_items(trait_did)
708                             .filter_by_name_unhygienic(impl_item.ident.name)
709                             .next()
710                             .map(|item| item.def_id);
711                         if let Some(def_id) = trait_item_def_id {
712                             // Pass `None` to skip deprecation warnings.
713                             self.tcx.check_stability(def_id, None, impl_item.span);
714                         }
715                     }
716                 }
717             }
718
719             // There's no good place to insert stability check for non-Copy unions,
720             // so semi-randomly perform it here in stability.rs
721             hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => {
722                 let def_id = self.tcx.hir().local_def_id(item.hir_id);
723                 let ty = self.tcx.type_of(def_id);
724                 let (adt_def, substs) = match ty.kind() {
725                     ty::Adt(adt_def, substs) => (adt_def, substs),
726                     _ => bug!(),
727                 };
728
729                 // Non-`Copy` fields are unstable, except for `ManuallyDrop`.
730                 let param_env = self.tcx.param_env(def_id);
731                 for field in &adt_def.non_enum_variant().fields {
732                     let field_ty = field.ty(self.tcx, substs);
733                     if !field_ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop())
734                         && !field_ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), param_env)
735                     {
736                         if field_ty.needs_drop(self.tcx, param_env) {
737                             // Avoid duplicate error: This will error later anyway because fields
738                             // that need drop are not allowed.
739                             self.tcx.sess.delay_span_bug(
740                                 item.span,
741                                 "union should have been rejected due to potentially dropping field",
742                             );
743                         } else {
744                             feature_err(
745                                 &self.tcx.sess.parse_sess,
746                                 sym::untagged_unions,
747                                 self.tcx.def_span(field.did),
748                                 "unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable",
749                             )
750                             .emit();
751                         }
752                     }
753                 }
754             }
755
756             _ => (/* pass */),
757         }
758         intravisit::walk_item(self, item);
759     }
760
761     fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) {
762         if let Some(def_id) = path.res.opt_def_id() {
763             self.tcx.check_stability(def_id, Some(id), path.span)
764         }
765         intravisit::walk_path(self, path)
766     }
767 }
768
769 struct CheckTraitImplStable<'tcx> {
770     tcx: TyCtxt<'tcx>,
771     fully_stable: bool,
772 }
773
774 impl Visitor<'tcx> for CheckTraitImplStable<'tcx> {
775     type Map = Map<'tcx>;
776
777     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
778         NestedVisitorMap::None
779     }
780
781     fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) {
782         if let Some(def_id) = path.res.opt_def_id() {
783             if let Some(stab) = self.tcx.lookup_stability(def_id) {
784                 self.fully_stable &= stab.level.is_stable();
785             }
786         }
787         intravisit::walk_path(self, path)
788     }
789
790     fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
791         if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
792             if let Some(stab) = self.tcx.lookup_stability(trait_did) {
793                 self.fully_stable &= stab.level.is_stable();
794             }
795         }
796         intravisit::walk_trait_ref(self, t)
797     }
798
799     fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
800         if let TyKind::Never = t.kind {
801             self.fully_stable = false;
802         }
803         intravisit::walk_ty(self, t)
804     }
805 }
806
807 /// Given the list of enabled features that were not language features (i.e., that
808 /// were expected to be library features), and the list of features used from
809 /// libraries, identify activated features that don't exist and error about them.
810 pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
811     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
812
813     if tcx.stability().staged_api[&LOCAL_CRATE] {
814         let krate = tcx.hir().krate();
815         let mut missing = MissingStabilityAnnotations { tcx, access_levels };
816         missing.check_missing_stability(hir::CRATE_HIR_ID, krate.item.span);
817         intravisit::walk_crate(&mut missing, krate);
818         krate.visit_all_item_likes(&mut missing.as_deep_visitor());
819     }
820
821     let declared_lang_features = &tcx.features().declared_lang_features;
822     let mut lang_features = FxHashSet::default();
823     for &(feature, span, since) in declared_lang_features {
824         if let Some(since) = since {
825             // Warn if the user has enabled an already-stable lang feature.
826             unnecessary_stable_feature_lint(tcx, span, feature, since);
827         }
828         if !lang_features.insert(feature) {
829             // Warn if the user enables a lang feature multiple times.
830             duplicate_feature_err(tcx.sess, span, feature);
831         }
832     }
833
834     let declared_lib_features = &tcx.features().declared_lib_features;
835     let mut remaining_lib_features = FxHashMap::default();
836     for (feature, span) in declared_lib_features {
837         if remaining_lib_features.contains_key(&feature) {
838             // Warn if the user enables a lib feature multiple times.
839             duplicate_feature_err(tcx.sess, *span, *feature);
840         }
841         remaining_lib_features.insert(feature, *span);
842     }
843     // `stdbuild` has special handling for `libc`, so we need to
844     // recognise the feature when building std.
845     // Likewise, libtest is handled specially, so `test` isn't
846     // available as we'd like it to be.
847     // FIXME: only remove `libc` when `stdbuild` is active.
848     // FIXME: remove special casing for `test`.
849     remaining_lib_features.remove(&sym::libc);
850     remaining_lib_features.remove(&sym::test);
851
852     let check_features = |remaining_lib_features: &mut FxHashMap<_, _>, defined_features: &[_]| {
853         for &(feature, since) in defined_features {
854             if let Some(since) = since {
855                 if let Some(span) = remaining_lib_features.get(&feature) {
856                     // Warn if the user has enabled an already-stable lib feature.
857                     unnecessary_stable_feature_lint(tcx, *span, feature, since);
858                 }
859             }
860             remaining_lib_features.remove(&feature);
861             if remaining_lib_features.is_empty() {
862                 break;
863             }
864         }
865     };
866
867     // We always collect the lib features declared in the current crate, even if there are
868     // no unknown features, because the collection also does feature attribute validation.
869     let local_defined_features = tcx.lib_features().to_vec();
870     if !remaining_lib_features.is_empty() {
871         check_features(&mut remaining_lib_features, &local_defined_features);
872
873         for &cnum in &*tcx.crates() {
874             if remaining_lib_features.is_empty() {
875                 break;
876             }
877             check_features(&mut remaining_lib_features, tcx.defined_lib_features(cnum));
878         }
879     }
880
881     for (feature, span) in remaining_lib_features {
882         struct_span_err!(tcx.sess, span, E0635, "unknown feature `{}`", feature).emit();
883     }
884
885     // FIXME(#44232): the `used_features` table no longer exists, so we
886     // don't lint about unused features. We should re-enable this one day!
887 }
888
889 fn unnecessary_stable_feature_lint(tcx: TyCtxt<'_>, span: Span, feature: Symbol, since: Symbol) {
890     tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
891         lint.build(&format!(
892             "the feature `{}` has been stable since {} and no longer requires \
893                       an attribute to enable",
894             feature, since
895         ))
896         .emit();
897     });
898 }
899
900 fn duplicate_feature_err(sess: &Session, span: Span, feature: Symbol) {
901     struct_span_err!(sess, span, E0636, "the feature `{}` has already been declared", feature)
902         .emit();
903 }