]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_passes/src/stability.rs
Rollup merge of #101722 - aDotInTheVoid:rdy-ty-prim-docs, r=CraftSpider
[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_attr::{
5     self as attr, rust_version_symbol, ConstStability, Stability, StabilityLevel, Unstable,
6     UnstableReason, VERSION_PLACEHOLDER,
7 };
8 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
9 use rustc_errors::{struct_span_err, Applicability};
10 use rustc_hir as hir;
11 use rustc_hir::def::{DefKind, Res};
12 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
13 use rustc_hir::hir_id::CRATE_HIR_ID;
14 use rustc_hir::intravisit::{self, Visitor};
15 use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
16 use rustc_middle::hir::nested_filter;
17 use rustc_middle::middle::privacy::AccessLevels;
18 use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
19 use rustc_middle::ty::{query::Providers, TyCtxt};
20 use rustc_session::lint;
21 use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
22 use rustc_session::Session;
23 use rustc_span::symbol::{sym, Symbol};
24 use rustc_span::Span;
25 use rustc_target::spec::abi::Abi;
26
27 use std::cmp::Ordering;
28 use std::iter;
29 use std::mem::replace;
30 use std::num::NonZeroU32;
31
32 #[derive(PartialEq)]
33 enum AnnotationKind {
34     /// Annotation is required if not inherited from unstable parents.
35     Required,
36     /// Annotation is useless, reject it.
37     Prohibited,
38     /// Deprecation annotation is useless, reject it. (Stability attribute is still required.)
39     DeprecationProhibited,
40     /// Annotation itself is useless, but it can be propagated to children.
41     Container,
42 }
43
44 /// Whether to inherit deprecation flags for nested items. In most cases, we do want to inherit
45 /// deprecation, because nested items rarely have individual deprecation attributes, and so
46 /// should be treated as deprecated if their parent is. However, default generic parameters
47 /// have separate deprecation attributes from their parents, so we do not wish to inherit
48 /// deprecation in this case. For example, inheriting deprecation for `T` in `Foo<T>`
49 /// would cause a duplicate warning arising from both `Foo` and `T` being deprecated.
50 #[derive(Clone)]
51 enum InheritDeprecation {
52     Yes,
53     No,
54 }
55
56 impl InheritDeprecation {
57     fn yes(&self) -> bool {
58         matches!(self, InheritDeprecation::Yes)
59     }
60 }
61
62 /// Whether to inherit const stability flags for nested items. In most cases, we do not want to
63 /// inherit const stability: just because an enclosing `fn` is const-stable does not mean
64 /// all `extern` imports declared in it should be const-stable! However, trait methods
65 /// inherit const stability attributes from their parent and do not have their own.
66 enum InheritConstStability {
67     Yes,
68     No,
69 }
70
71 impl InheritConstStability {
72     fn yes(&self) -> bool {
73         matches!(self, InheritConstStability::Yes)
74     }
75 }
76
77 enum InheritStability {
78     Yes,
79     No,
80 }
81
82 impl InheritStability {
83     fn yes(&self) -> bool {
84         matches!(self, InheritStability::Yes)
85     }
86 }
87
88 /// A private tree-walker for producing an `Index`.
89 struct Annotator<'a, 'tcx> {
90     tcx: TyCtxt<'tcx>,
91     index: &'a mut Index,
92     parent_stab: Option<Stability>,
93     parent_const_stab: Option<ConstStability>,
94     parent_depr: Option<DeprecationEntry>,
95     in_trait_impl: bool,
96 }
97
98 impl<'a, 'tcx> Annotator<'a, 'tcx> {
99     /// Determine the stability for a node based on its attributes and inherited stability. The
100     /// stability is recorded in the index and used as the parent. If the node is a function,
101     /// `fn_sig` is its signature.
102     fn annotate<F>(
103         &mut self,
104         def_id: LocalDefId,
105         item_sp: Span,
106         fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
107         kind: AnnotationKind,
108         inherit_deprecation: InheritDeprecation,
109         inherit_const_stability: InheritConstStability,
110         inherit_from_parent: InheritStability,
111         visit_children: F,
112     ) where
113         F: FnOnce(&mut Self),
114     {
115         let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id));
116         debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
117
118         let depr = attr::find_deprecation(&self.tcx.sess, attrs);
119         let mut is_deprecated = false;
120         if let Some((depr, span)) = &depr {
121             is_deprecated = true;
122
123             if kind == AnnotationKind::Prohibited || kind == AnnotationKind::DeprecationProhibited {
124                 let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
125                 self.tcx.struct_span_lint_hir(USELESS_DEPRECATED, hir_id, *span, |lint| {
126                     lint.build("this `#[deprecated]` annotation has no effect")
127                         .span_suggestion_short(
128                             *span,
129                             "remove the unnecessary deprecation attribute",
130                             "",
131                             rustc_errors::Applicability::MachineApplicable,
132                         )
133                         .emit();
134                 });
135             }
136
137             // `Deprecation` is just two pointers, no need to intern it
138             let depr_entry = DeprecationEntry::local(*depr, def_id);
139             self.index.depr_map.insert(def_id, depr_entry);
140         } else if let Some(parent_depr) = self.parent_depr {
141             if inherit_deprecation.yes() {
142                 is_deprecated = true;
143                 info!("tagging child {:?} as deprecated from parent", def_id);
144                 self.index.depr_map.insert(def_id, parent_depr);
145             }
146         }
147
148         if !self.tcx.features().staged_api {
149             // Propagate unstability.  This can happen even for non-staged-api crates in case
150             // -Zforce-unstable-if-unmarked is set.
151             if let Some(stab) = self.parent_stab {
152                 if inherit_deprecation.yes() && stab.is_unstable() {
153                     self.index.stab_map.insert(def_id, stab);
154                 }
155             }
156
157             self.recurse_with_stability_attrs(
158                 depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
159                 None,
160                 None,
161                 visit_children,
162             );
163             return;
164         }
165
166         let (stab, const_stab, body_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
167         let mut const_span = None;
168
169         let const_stab = const_stab.map(|(const_stab, const_span_node)| {
170             self.index.const_stab_map.insert(def_id, const_stab);
171             const_span = Some(const_span_node);
172             const_stab
173         });
174
175         // If the current node is a function, has const stability attributes and if it doesn not have an intrinsic ABI,
176         // check if the function/method is const or the parent impl block is const
177         if let (Some(const_span), Some(fn_sig)) = (const_span, fn_sig) {
178             if fn_sig.header.abi != Abi::RustIntrinsic
179                 && fn_sig.header.abi != Abi::PlatformIntrinsic
180                 && !fn_sig.header.is_const()
181             {
182                 if !self.in_trait_impl
183                     || (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id()))
184                 {
185                     missing_const_err(&self.tcx.sess, fn_sig.span, const_span);
186                 }
187             }
188         }
189
190         // `impl const Trait for Type` items forward their const stability to their
191         // immediate children.
192         if const_stab.is_none() {
193             debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
194             if let Some(parent) = self.parent_const_stab {
195                 if parent.is_const_unstable() {
196                     self.index.const_stab_map.insert(def_id, parent);
197                 }
198             }
199         }
200
201         if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr {
202             if stab.is_none() {
203                 struct_span_err!(
204                     self.tcx.sess,
205                     *span,
206                     E0549,
207                     "deprecated attribute must be paired with \
208                     either stable or unstable attribute"
209                 )
210                 .emit();
211             }
212         }
213
214         if let Some((body_stab, _span)) = body_stab {
215             // FIXME: check that this item can have body stability
216
217             self.index.default_body_stab_map.insert(def_id, body_stab);
218             debug!(?self.index.default_body_stab_map);
219         }
220
221         let stab = stab.map(|(stab, span)| {
222             // Error if prohibited, or can't inherit anything from a container.
223             if kind == AnnotationKind::Prohibited
224                 || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
225             {
226                 self.tcx.sess.struct_span_err(span,"this stability annotation is useless")
227                     .span_label(span, "useless stability annotation")
228                     .span_label(item_sp, "the stability attribute annotates this item")
229                     .emit();
230             }
231
232             debug!("annotate: found {:?}", stab);
233
234             // Check if deprecated_since < stable_since. If it is,
235             // this is *almost surely* an accident.
236             if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) =
237                 (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level)
238             {
239                 // Explicit version of iter::order::lt to handle parse errors properly
240                 for (dep_v, stab_v) in
241                     iter::zip(dep_since.as_str().split('.'), stab_since.as_str().split('.'))
242                 {
243                     match stab_v.parse::<u64>() {
244                         Err(_) => {
245                             self.tcx.sess.struct_span_err(span, "invalid stability version found")
246                                 .span_label(span, "invalid stability version")
247                                 .span_label(item_sp, "the stability attribute annotates this item")
248                                 .emit();
249                             break;
250                         }
251                         Ok(stab_vp) => match dep_v.parse::<u64>() {
252                             Ok(dep_vp) => match dep_vp.cmp(&stab_vp) {
253                                 Ordering::Less => {
254                                     self.tcx.sess.struct_span_err(span, "an API can't be stabilized after it is deprecated")
255                                         .span_label(span, "invalid version")
256                                         .span_label(item_sp, "the stability attribute annotates this item")
257                                         .emit();
258                                     break;
259                                 }
260                                 Ordering::Equal => continue,
261                                 Ordering::Greater => break,
262                             },
263                             Err(_) => {
264                                 if dep_v != "TBD" {
265                                     self.tcx.sess.struct_span_err(span, "invalid deprecation version found")
266                                         .span_label(span, "invalid deprecation version")
267                                         .span_label(item_sp, "the stability attribute annotates this item")
268                                         .emit();
269                                 }
270                                 break;
271                             }
272                         },
273                     }
274                 }
275             }
276
277             if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab {
278                 self.index.implications.insert(implied_by, feature);
279             }
280
281             self.index.stab_map.insert(def_id, stab);
282             stab
283         });
284
285         if stab.is_none() {
286             debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
287             if let Some(stab) = self.parent_stab {
288                 if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() {
289                     self.index.stab_map.insert(def_id, stab);
290                 }
291             }
292         }
293
294         self.recurse_with_stability_attrs(
295             depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
296             stab,
297             if inherit_const_stability.yes() { const_stab } else { None },
298             visit_children,
299         );
300     }
301
302     fn recurse_with_stability_attrs(
303         &mut self,
304         depr: Option<DeprecationEntry>,
305         stab: Option<Stability>,
306         const_stab: Option<ConstStability>,
307         f: impl FnOnce(&mut Self),
308     ) {
309         // These will be `Some` if this item changes the corresponding stability attribute.
310         let mut replaced_parent_depr = None;
311         let mut replaced_parent_stab = None;
312         let mut replaced_parent_const_stab = None;
313
314         if let Some(depr) = depr {
315             replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
316         }
317         if let Some(stab) = stab {
318             replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
319         }
320         if let Some(const_stab) = const_stab {
321             replaced_parent_const_stab =
322                 Some(replace(&mut self.parent_const_stab, Some(const_stab)));
323         }
324
325         f(self);
326
327         if let Some(orig_parent_depr) = replaced_parent_depr {
328             self.parent_depr = orig_parent_depr;
329         }
330         if let Some(orig_parent_stab) = replaced_parent_stab {
331             self.parent_stab = orig_parent_stab;
332         }
333         if let Some(orig_parent_const_stab) = replaced_parent_const_stab {
334             self.parent_const_stab = orig_parent_const_stab;
335         }
336     }
337 }
338
339 impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
340     /// Because stability levels are scoped lexically, we want to walk
341     /// nested items in the context of the outer item, so enable
342     /// deep-walking.
343     type NestedFilter = nested_filter::All;
344
345     fn nested_visit_map(&mut self) -> Self::Map {
346         self.tcx.hir()
347     }
348
349     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
350         let orig_in_trait_impl = self.in_trait_impl;
351         let mut kind = AnnotationKind::Required;
352         let mut const_stab_inherit = InheritConstStability::No;
353         let mut fn_sig = None;
354
355         match i.kind {
356             // Inherent impls and foreign modules serve only as containers for other items,
357             // they don't have their own stability. They still can be annotated as unstable
358             // and propagate this instability to children, but this annotation is completely
359             // optional. They inherit stability from their parents when unannotated.
360             hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
361             | hir::ItemKind::ForeignMod { .. } => {
362                 self.in_trait_impl = false;
363                 kind = AnnotationKind::Container;
364             }
365             hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
366                 self.in_trait_impl = true;
367                 kind = AnnotationKind::DeprecationProhibited;
368                 const_stab_inherit = InheritConstStability::Yes;
369             }
370             hir::ItemKind::Struct(ref sd, _) => {
371                 if let Some(ctor_hir_id) = sd.ctor_hir_id() {
372                     self.annotate(
373                         self.tcx.hir().local_def_id(ctor_hir_id),
374                         i.span,
375                         None,
376                         AnnotationKind::Required,
377                         InheritDeprecation::Yes,
378                         InheritConstStability::No,
379                         InheritStability::Yes,
380                         |_| {},
381                     )
382                 }
383             }
384             hir::ItemKind::Fn(ref item_fn_sig, _, _) => {
385                 fn_sig = Some(item_fn_sig);
386             }
387             _ => {}
388         }
389
390         self.annotate(
391             i.def_id,
392             i.span,
393             fn_sig,
394             kind,
395             InheritDeprecation::Yes,
396             const_stab_inherit,
397             InheritStability::No,
398             |v| intravisit::walk_item(v, i),
399         );
400         self.in_trait_impl = orig_in_trait_impl;
401     }
402
403     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
404         let fn_sig = match ti.kind {
405             hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
406             _ => None,
407         };
408
409         self.annotate(
410             ti.def_id,
411             ti.span,
412             fn_sig,
413             AnnotationKind::Required,
414             InheritDeprecation::Yes,
415             InheritConstStability::No,
416             InheritStability::No,
417             |v| {
418                 intravisit::walk_trait_item(v, ti);
419             },
420         );
421     }
422
423     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
424         let kind =
425             if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
426
427         let fn_sig = match ii.kind {
428             hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
429             _ => None,
430         };
431
432         self.annotate(
433             ii.def_id,
434             ii.span,
435             fn_sig,
436             kind,
437             InheritDeprecation::Yes,
438             InheritConstStability::No,
439             InheritStability::No,
440             |v| {
441                 intravisit::walk_impl_item(v, ii);
442             },
443         );
444     }
445
446     fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
447         self.annotate(
448             self.tcx.hir().local_def_id(var.id),
449             var.span,
450             None,
451             AnnotationKind::Required,
452             InheritDeprecation::Yes,
453             InheritConstStability::No,
454             InheritStability::Yes,
455             |v| {
456                 if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
457                     v.annotate(
458                         v.tcx.hir().local_def_id(ctor_hir_id),
459                         var.span,
460                         None,
461                         AnnotationKind::Required,
462                         InheritDeprecation::Yes,
463                         InheritConstStability::No,
464                         InheritStability::Yes,
465                         |_| {},
466                     );
467                 }
468
469                 intravisit::walk_variant(v, var)
470             },
471         )
472     }
473
474     fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
475         self.annotate(
476             self.tcx.hir().local_def_id(s.hir_id),
477             s.span,
478             None,
479             AnnotationKind::Required,
480             InheritDeprecation::Yes,
481             InheritConstStability::No,
482             InheritStability::Yes,
483             |v| {
484                 intravisit::walk_field_def(v, s);
485             },
486         );
487     }
488
489     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
490         self.annotate(
491             i.def_id,
492             i.span,
493             None,
494             AnnotationKind::Required,
495             InheritDeprecation::Yes,
496             InheritConstStability::No,
497             InheritStability::No,
498             |v| {
499                 intravisit::walk_foreign_item(v, i);
500             },
501         );
502     }
503
504     fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
505         let kind = match &p.kind {
506             // Allow stability attributes on default generic arguments.
507             hir::GenericParamKind::Type { default: Some(_), .. }
508             | hir::GenericParamKind::Const { default: Some(_), .. } => AnnotationKind::Container,
509             _ => AnnotationKind::Prohibited,
510         };
511
512         self.annotate(
513             self.tcx.hir().local_def_id(p.hir_id),
514             p.span,
515             None,
516             kind,
517             InheritDeprecation::No,
518             InheritConstStability::No,
519             InheritStability::No,
520             |v| {
521                 intravisit::walk_generic_param(v, p);
522             },
523         );
524     }
525 }
526
527 struct MissingStabilityAnnotations<'tcx> {
528     tcx: TyCtxt<'tcx>,
529     access_levels: &'tcx AccessLevels,
530 }
531
532 impl<'tcx> MissingStabilityAnnotations<'tcx> {
533     fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
534         let stab = self.tcx.stability().local_stability(def_id);
535         if !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(def_id) {
536             let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
537             self.tcx.sess.span_err(span, &format!("{} has missing stability attribute", descr));
538         }
539     }
540
541     fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
542         if !self.tcx.features().staged_api {
543             return;
544         }
545
546         let is_const = self.tcx.is_const_fn(def_id.to_def_id())
547             || self.tcx.is_const_trait_impl_raw(def_id.to_def_id());
548         let is_stable = self
549             .tcx
550             .lookup_stability(def_id)
551             .map_or(false, |stability| stability.level.is_stable());
552         let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
553         let is_reachable = self.access_levels.is_reachable(def_id);
554
555         if is_const && is_stable && missing_const_stability_attribute && is_reachable {
556             let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
557             self.tcx.sess.span_err(span, &format!("{descr} has missing const stability attribute"));
558         }
559     }
560 }
561
562 impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
563     type NestedFilter = nested_filter::OnlyBodies;
564
565     fn nested_visit_map(&mut self) -> Self::Map {
566         self.tcx.hir()
567     }
568
569     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
570         // Inherent impls and foreign modules serve only as containers for other items,
571         // they don't have their own stability. They still can be annotated as unstable
572         // and propagate this instability to children, but this annotation is completely
573         // optional. They inherit stability from their parents when unannotated.
574         if !matches!(
575             i.kind,
576             hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
577                 | hir::ItemKind::ForeignMod { .. }
578         ) {
579             self.check_missing_stability(i.def_id, i.span);
580         }
581
582         // Ensure stable `const fn` have a const stability attribute.
583         self.check_missing_const_stability(i.def_id, i.span);
584
585         intravisit::walk_item(self, i)
586     }
587
588     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
589         self.check_missing_stability(ti.def_id, ti.span);
590         intravisit::walk_trait_item(self, ti);
591     }
592
593     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
594         let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id());
595         if self.tcx.impl_trait_ref(impl_def_id).is_none() {
596             self.check_missing_stability(ii.def_id, ii.span);
597             self.check_missing_const_stability(ii.def_id, ii.span);
598         }
599         intravisit::walk_impl_item(self, ii);
600     }
601
602     fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
603         self.check_missing_stability(self.tcx.hir().local_def_id(var.id), var.span);
604         if let Some(ctor_hir_id) = var.data.ctor_hir_id() {
605             self.check_missing_stability(self.tcx.hir().local_def_id(ctor_hir_id), var.span);
606         }
607         intravisit::walk_variant(self, var);
608     }
609
610     fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
611         self.check_missing_stability(self.tcx.hir().local_def_id(s.hir_id), s.span);
612         intravisit::walk_field_def(self, s);
613     }
614
615     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
616         self.check_missing_stability(i.def_id, i.span);
617         intravisit::walk_foreign_item(self, i);
618     }
619     // Note that we don't need to `check_missing_stability` for default generic parameters,
620     // as we assume that any default generic parameters without attributes are automatically
621     // stable (assuming they have not inherited instability from their parent).
622 }
623
624 fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
625     let mut index = Index {
626         stab_map: Default::default(),
627         const_stab_map: Default::default(),
628         default_body_stab_map: Default::default(),
629         depr_map: Default::default(),
630         implications: Default::default(),
631     };
632
633     {
634         let mut annotator = Annotator {
635             tcx,
636             index: &mut index,
637             parent_stab: None,
638             parent_const_stab: None,
639             parent_depr: None,
640             in_trait_impl: false,
641         };
642
643         // If the `-Z force-unstable-if-unmarked` flag is passed then we provide
644         // a parent stability annotation which indicates that this is private
645         // with the `rustc_private` feature. This is intended for use when
646         // compiling `librustc_*` crates themselves so we can leverage crates.io
647         // while maintaining the invariant that all sysroot crates are unstable
648         // by default and are unable to be used.
649         if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
650             let stability = Stability {
651                 level: attr::StabilityLevel::Unstable {
652                     reason: UnstableReason::Default,
653                     issue: NonZeroU32::new(27812),
654                     is_soft: false,
655                     implied_by: None,
656                 },
657                 feature: sym::rustc_private,
658             };
659             annotator.parent_stab = Some(stability);
660         }
661
662         annotator.annotate(
663             CRATE_DEF_ID,
664             tcx.hir().span(CRATE_HIR_ID),
665             None,
666             AnnotationKind::Required,
667             InheritDeprecation::Yes,
668             InheritConstStability::No,
669             InheritStability::No,
670             |v| tcx.hir().walk_toplevel_module(v),
671         );
672     }
673     index
674 }
675
676 /// Cross-references the feature names of unstable APIs with enabled
677 /// features and possibly prints errors.
678 fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
679     tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
680 }
681
682 pub(crate) fn provide(providers: &mut Providers) {
683     *providers = Providers {
684         check_mod_unstable_api_usage,
685         stability_index,
686         stability_implications: |tcx, _| tcx.stability().implications.clone(),
687         lookup_stability: |tcx, id| tcx.stability().local_stability(id.expect_local()),
688         lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id.expect_local()),
689         lookup_default_body_stability: |tcx, id| {
690             tcx.stability().local_default_body_stability(id.expect_local())
691         },
692         lookup_deprecation_entry: |tcx, id| {
693             tcx.stability().local_deprecation_entry(id.expect_local())
694         },
695         ..*providers
696     };
697 }
698
699 struct Checker<'tcx> {
700     tcx: TyCtxt<'tcx>,
701 }
702
703 impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
704     type NestedFilter = nested_filter::OnlyBodies;
705
706     /// Because stability levels are scoped lexically, we want to walk
707     /// nested items in the context of the outer item, so enable
708     /// deep-walking.
709     fn nested_visit_map(&mut self) -> Self::Map {
710         self.tcx.hir()
711     }
712
713     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
714         match item.kind {
715             hir::ItemKind::ExternCrate(_) => {
716                 // compiler-generated `extern crate` items have a dummy span.
717                 // `std` is still checked for the `restricted-std` feature.
718                 if item.span.is_dummy() && item.ident.name != sym::std {
719                     return;
720                 }
721
722                 let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id) else {
723                     return;
724                 };
725                 let def_id = cnum.as_def_id();
726                 self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
727             }
728
729             // For implementations of traits, check the stability of each item
730             // individually as it's possible to have a stable trait with unstable
731             // items.
732             hir::ItemKind::Impl(hir::Impl {
733                 of_trait: Some(ref t),
734                 self_ty,
735                 items,
736                 constness,
737                 ..
738             }) => {
739                 let features = self.tcx.features();
740                 if features.staged_api {
741                     let attrs = self.tcx.hir().attrs(item.hir_id());
742                     let (stab, const_stab, _) =
743                         attr::find_stability(&self.tcx.sess, attrs, item.span);
744
745                     // If this impl block has an #[unstable] attribute, give an
746                     // error if all involved types and traits are stable, because
747                     // it will have no effect.
748                     // See: https://github.com/rust-lang/rust/issues/55436
749                     if let Some((Stability { level: attr::Unstable { .. }, .. }, span)) = stab {
750                         let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
751                         c.visit_ty(self_ty);
752                         c.visit_trait_ref(t);
753                         if c.fully_stable {
754                             self.tcx.struct_span_lint_hir(
755                                 INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
756                                 item.hir_id(),
757                                 span,
758                                 |lint| {lint
759                                     .build("an `#[unstable]` annotation here has no effect")
760                                     .note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
761                                     .emit();}
762                             );
763                         }
764                     }
765
766                     // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
767                     // needs to have an error emitted.
768                     if features.const_trait_impl
769                         && *constness == hir::Constness::Const
770                         && const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
771                     {
772                         self.tcx
773                             .sess
774                             .struct_span_err(item.span, "trait implementations cannot be const stable yet")
775                             .note("see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information")
776                             .emit();
777                     }
778                 }
779
780                 for impl_item_ref in *items {
781                     let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
782
783                     if let Some(def_id) = impl_item.trait_item_def_id {
784                         // Pass `None` to skip deprecation warnings.
785                         self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
786                     }
787                 }
788             }
789
790             _ => (/* pass */),
791         }
792         intravisit::walk_item(self, item);
793     }
794
795     fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) {
796         if let Some(def_id) = path.res.opt_def_id() {
797             let method_span = path.segments.last().map(|s| s.ident.span);
798             let item_is_allowed = self.tcx.check_stability_allow_unstable(
799                 def_id,
800                 Some(id),
801                 path.span,
802                 method_span,
803                 if is_unstable_reexport(self.tcx, id) {
804                     AllowUnstable::Yes
805                 } else {
806                     AllowUnstable::No
807                 },
808             );
809
810             let is_allowed_through_unstable_modules = |def_id| {
811                 self.tcx
812                     .lookup_stability(def_id)
813                     .map(|stab| match stab.level {
814                         StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
815                             allowed_through_unstable_modules
816                         }
817                         _ => false,
818                     })
819                     .unwrap_or(false)
820             };
821
822             if item_is_allowed && !is_allowed_through_unstable_modules(def_id) {
823                 // Check parent modules stability as well if the item the path refers to is itself
824                 // stable. We only emit warnings for unstable path segments if the item is stable
825                 // or allowed because stability is often inherited, so the most common case is that
826                 // both the segments and the item are unstable behind the same feature flag.
827                 //
828                 // We check here rather than in `visit_path_segment` to prevent visiting the last
829                 // path segment twice
830                 //
831                 // We include special cases via #[rustc_allowed_through_unstable_modules] for items
832                 // that were accidentally stabilized through unstable paths before this check was
833                 // added, such as `core::intrinsics::transmute`
834                 let parents = path.segments.iter().rev().skip(1);
835                 for path_segment in parents {
836                     if let Some(def_id) = path_segment.res.opt_def_id() {
837                         // use `None` for id to prevent deprecation check
838                         self.tcx.check_stability_allow_unstable(
839                             def_id,
840                             None,
841                             path.span,
842                             None,
843                             if is_unstable_reexport(self.tcx, id) {
844                                 AllowUnstable::Yes
845                             } else {
846                                 AllowUnstable::No
847                             },
848                         );
849                     }
850                 }
851             }
852         }
853
854         intravisit::walk_path(self, path)
855     }
856 }
857
858 /// Check whether a path is a `use` item that has been marked as unstable.
859 ///
860 /// See issue #94972 for details on why this is a special case
861 fn is_unstable_reexport<'tcx>(tcx: TyCtxt<'tcx>, id: hir::HirId) -> bool {
862     // Get the LocalDefId so we can lookup the item to check the kind.
863     let Some(def_id) = tcx.hir().opt_local_def_id(id) else { return false; };
864
865     let Some(stab) = tcx.stability().local_stability(def_id) else {
866         return false;
867     };
868
869     if stab.level.is_stable() {
870         // The re-export is not marked as unstable, don't override
871         return false;
872     }
873
874     // If this is a path that isn't a use, we don't need to do anything special
875     if !matches!(tcx.hir().item(hir::ItemId { def_id }).kind, ItemKind::Use(..)) {
876         return false;
877     }
878
879     true
880 }
881
882 struct CheckTraitImplStable<'tcx> {
883     tcx: TyCtxt<'tcx>,
884     fully_stable: bool,
885 }
886
887 impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
888     fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) {
889         if let Some(def_id) = path.res.opt_def_id() {
890             if let Some(stab) = self.tcx.lookup_stability(def_id) {
891                 self.fully_stable &= stab.level.is_stable();
892             }
893         }
894         intravisit::walk_path(self, path)
895     }
896
897     fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
898         if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
899             if let Some(stab) = self.tcx.lookup_stability(trait_did) {
900                 self.fully_stable &= stab.level.is_stable();
901             }
902         }
903         intravisit::walk_trait_ref(self, t)
904     }
905
906     fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
907         if let TyKind::Never = t.kind {
908             self.fully_stable = false;
909         }
910         intravisit::walk_ty(self, t)
911     }
912 }
913
914 /// Given the list of enabled features that were not language features (i.e., that
915 /// were expected to be library features), and the list of features used from
916 /// libraries, identify activated features that don't exist and error about them.
917 pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
918     let is_staged_api =
919         tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api;
920     if is_staged_api {
921         let access_levels = &tcx.privacy_access_levels(());
922         let mut missing = MissingStabilityAnnotations { tcx, access_levels };
923         missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
924         tcx.hir().walk_toplevel_module(&mut missing);
925         tcx.hir().visit_all_item_likes_in_crate(&mut missing);
926     }
927
928     let declared_lang_features = &tcx.features().declared_lang_features;
929     let mut lang_features = FxHashSet::default();
930     for &(feature, span, since) in declared_lang_features {
931         if let Some(since) = since {
932             // Warn if the user has enabled an already-stable lang feature.
933             unnecessary_stable_feature_lint(tcx, span, feature, since);
934         }
935         if !lang_features.insert(feature) {
936             // Warn if the user enables a lang feature multiple times.
937             duplicate_feature_err(tcx.sess, span, feature);
938         }
939     }
940
941     let declared_lib_features = &tcx.features().declared_lib_features;
942     let mut remaining_lib_features = FxIndexMap::default();
943     for (feature, span) in declared_lib_features {
944         if !tcx.sess.opts.unstable_features.is_nightly_build() {
945             struct_span_err!(
946                 tcx.sess,
947                 *span,
948                 E0554,
949                 "`#![feature]` may not be used on the {} release channel",
950                 env!("CFG_RELEASE_CHANNEL")
951             )
952             .emit();
953         }
954         if remaining_lib_features.contains_key(&feature) {
955             // Warn if the user enables a lib feature multiple times.
956             duplicate_feature_err(tcx.sess, *span, *feature);
957         }
958         remaining_lib_features.insert(feature, *span);
959     }
960     // `stdbuild` has special handling for `libc`, so we need to
961     // recognise the feature when building std.
962     // Likewise, libtest is handled specially, so `test` isn't
963     // available as we'd like it to be.
964     // FIXME: only remove `libc` when `stdbuild` is active.
965     // FIXME: remove special casing for `test`.
966     remaining_lib_features.remove(&sym::libc);
967     remaining_lib_features.remove(&sym::test);
968
969     /// For each feature in `defined_features`..
970     ///
971     /// - If it is in `remaining_lib_features` (those features with `#![feature(..)]` attributes in
972     ///   the current crate), check if it is stable (or partially stable) and thus an unnecessary
973     ///   attribute.
974     /// - If it is in `remaining_implications` (a feature that is referenced by an `implied_by`
975     ///   from the current crate), then remove it from the remaining implications.
976     ///
977     /// Once this function has been invoked for every feature (local crate and all extern crates),
978     /// then..
979     ///
980     /// - If features remain in `remaining_lib_features`, then the user has enabled a feature that
981     ///   does not exist.
982     /// - If features remain in `remaining_implications`, the `implied_by` refers to a feature that
983     ///   does not exist.
984     ///
985     /// By structuring the code in this way: checking the features defined from each crate one at a
986     /// time, less loading from metadata is performed and thus compiler performance is improved.
987     fn check_features<'tcx>(
988         tcx: TyCtxt<'tcx>,
989         remaining_lib_features: &mut FxIndexMap<&Symbol, Span>,
990         remaining_implications: &mut FxHashMap<Symbol, Symbol>,
991         defined_features: &[(Symbol, Option<Symbol>)],
992         all_implications: &FxHashMap<Symbol, Symbol>,
993     ) {
994         for (feature, since) in defined_features {
995             if let Some(since) = since && let Some(span) = remaining_lib_features.get(&feature) {
996                 // Warn if the user has enabled an already-stable lib feature.
997                 if let Some(implies) = all_implications.get(&feature) {
998                     unnecessary_partially_stable_feature_lint(tcx, *span, *feature, *implies, *since);
999                 } else {
1000                     unnecessary_stable_feature_lint(tcx, *span, *feature, *since);
1001                 }
1002
1003             }
1004             remaining_lib_features.remove(feature);
1005
1006             // `feature` is the feature doing the implying, but `implied_by` is the feature with
1007             // the attribute that establishes this relationship. `implied_by` is guaranteed to be a
1008             // feature defined in the local crate because `remaining_implications` is only the
1009             // implications from this crate.
1010             remaining_implications.remove(feature);
1011
1012             if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
1013                 break;
1014             }
1015         }
1016     }
1017
1018     // All local crate implications need to have the feature that implies it confirmed to exist.
1019     let mut remaining_implications =
1020         tcx.stability_implications(rustc_hir::def_id::LOCAL_CRATE).clone();
1021
1022     // We always collect the lib features declared in the current crate, even if there are
1023     // no unknown features, because the collection also does feature attribute validation.
1024     let local_defined_features = tcx.lib_features(()).to_vec();
1025     if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() {
1026         // Loading the implications of all crates is unavoidable to be able to emit the partial
1027         // stabilization diagnostic, but it can be avoided when there are no
1028         // `remaining_lib_features`.
1029         let mut all_implications = remaining_implications.clone();
1030         for &cnum in tcx.crates(()) {
1031             all_implications.extend(tcx.stability_implications(cnum));
1032         }
1033
1034         check_features(
1035             tcx,
1036             &mut remaining_lib_features,
1037             &mut remaining_implications,
1038             local_defined_features.as_slice(),
1039             &all_implications,
1040         );
1041
1042         for &cnum in tcx.crates(()) {
1043             if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
1044                 break;
1045             }
1046             check_features(
1047                 tcx,
1048                 &mut remaining_lib_features,
1049                 &mut remaining_implications,
1050                 tcx.defined_lib_features(cnum).to_vec().as_slice(),
1051                 &all_implications,
1052             );
1053         }
1054     }
1055
1056     for (feature, span) in remaining_lib_features {
1057         struct_span_err!(tcx.sess, span, E0635, "unknown feature `{}`", feature).emit();
1058     }
1059
1060     for (implied_by, feature) in remaining_implications {
1061         let local_defined_features = tcx.lib_features(());
1062         let span = local_defined_features
1063             .stable
1064             .get(&feature)
1065             .map(|(_, span)| span)
1066             .or_else(|| local_defined_features.unstable.get(&feature))
1067             .expect("feature that implied another does not exist");
1068         tcx.sess
1069             .struct_span_err(
1070                 *span,
1071                 format!("feature `{implied_by}` implying `{feature}` does not exist"),
1072             )
1073             .emit();
1074     }
1075
1076     // FIXME(#44232): the `used_features` table no longer exists, so we
1077     // don't lint about unused features. We should re-enable this one day!
1078 }
1079
1080 fn unnecessary_partially_stable_feature_lint(
1081     tcx: TyCtxt<'_>,
1082     span: Span,
1083     feature: Symbol,
1084     implies: Symbol,
1085     since: Symbol,
1086 ) {
1087     tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
1088         lint.build(&format!(
1089             "the feature `{feature}` has been partially stabilized since {since} and is succeeded \
1090              by the feature `{implies}`"
1091         ))
1092         .span_suggestion(
1093             span,
1094             &format!(
1095                 "if you are using features which are still unstable, change to using `{implies}`"
1096             ),
1097             implies,
1098             Applicability::MaybeIncorrect,
1099         )
1100         .span_suggestion(
1101             tcx.sess.source_map().span_extend_to_line(span),
1102             "if you are using features which are now stable, remove this line",
1103             "",
1104             Applicability::MaybeIncorrect,
1105         )
1106         .emit();
1107     });
1108 }
1109
1110 fn unnecessary_stable_feature_lint(
1111     tcx: TyCtxt<'_>,
1112     span: Span,
1113     feature: Symbol,
1114     mut since: Symbol,
1115 ) {
1116     if since.as_str() == VERSION_PLACEHOLDER {
1117         since = rust_version_symbol();
1118     }
1119     tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
1120         lint.build(&format!(
1121             "the feature `{feature}` has been stable since {since} and no longer requires an \
1122              attribute to enable",
1123         ))
1124         .emit();
1125     });
1126 }
1127
1128 fn duplicate_feature_err(sess: &Session, span: Span, feature: Symbol) {
1129     struct_span_err!(sess, span, E0636, "the feature `{}` has already been declared", feature)
1130         .emit();
1131 }
1132
1133 fn missing_const_err(session: &Session, fn_sig_span: Span, const_span: Span) {
1134     const ERROR_MSG: &'static str = "attributes `#[rustc_const_unstable]` \
1135          and `#[rustc_const_stable]` require \
1136          the function or method to be `const`";
1137
1138     session
1139         .struct_span_err(fn_sig_span, ERROR_MSG)
1140         .span_help(fn_sig_span, "make the function or method const")
1141         .span_label(const_span, "attribute specified here")
1142         .emit();
1143 }