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