1use std::mem::replace;
5use std::num::NonZero;
6
7use rustc_ast_lowering::stability::extern_abi_stability;
8use rustc_attr_parsing::{
9 self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince,
10 UnstableReason, VERSION_PLACEHOLDER,
11};
12use rustc_data_structures::fx::FxIndexMap;
13use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
14use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature};
15use rustc_hir::def::{DefKind, Res};
16use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
17use rustc_hir::hir_id::CRATE_HIR_ID;
18use rustc_hir::intravisit::{self, Visitor, VisitorExt};
19use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
20use rustc_middle::hir::nested_filter;
21use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
22use rustc_middle::middle::privacy::EffectiveVisibilities;
23use rustc_middle::middle::stability::{
24 AllowUnstable, Deprecated, DeprecationEntry, EvalResult, Index,
25};
26use rustc_middle::query::Providers;
27use rustc_middle::ty::TyCtxt;
28use rustc_middle::ty::print::with_no_trimmed_paths;
29use rustc_session::lint;
30use rustc_session::lint::builtin::{
31 DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED,
32};
33use rustc_span::{Span, Symbol, sym};
34use tracing::{debug, info};
35
36use crate::errors;
37
38#[derive(PartialEq)]
39enum AnnotationKind {
40 Required,
42 Prohibited,
44 DeprecationProhibited,
46 Container,
48}
49
50#[derive(Clone)]
57enum InheritDeprecation {
58 Yes,
59 No,
60}
61
62impl InheritDeprecation {
63 fn yes(&self) -> bool {
64 matches!(self, InheritDeprecation::Yes)
65 }
66}
67
68enum InheritConstStability {
73 Yes,
74 No,
75}
76
77impl InheritConstStability {
78 fn yes(&self) -> bool {
79 matches!(self, InheritConstStability::Yes)
80 }
81}
82
83enum InheritStability {
84 Yes,
85 No,
86}
87
88impl InheritStability {
89 fn yes(&self) -> bool {
90 matches!(self, InheritStability::Yes)
91 }
92}
93
94struct Annotator<'a, 'tcx> {
96 tcx: TyCtxt<'tcx>,
97 index: &'a mut Index,
98 parent_stab: Option<Stability>,
99 parent_const_stab: Option<ConstStability>,
100 parent_depr: Option<DeprecationEntry>,
101 in_trait_impl: bool,
102}
103
104impl<'a, 'tcx> Annotator<'a, 'tcx> {
105 fn annotate<F>(
109 &mut self,
110 def_id: LocalDefId,
111 item_sp: Span,
112 fn_sig: Option<&'tcx hir::FnSig<'tcx>>,
113 kind: AnnotationKind,
114 inherit_deprecation: InheritDeprecation,
115 inherit_const_stability: InheritConstStability,
116 inherit_from_parent: InheritStability,
117 visit_children: F,
118 ) where
119 F: FnOnce(&mut Self),
120 {
121 let attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id));
122 debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
123
124 let depr = attr::find_deprecation(self.tcx.sess, self.tcx.features(), attrs);
125 let mut is_deprecated = false;
126 if let Some((depr, span)) = &depr {
127 is_deprecated = true;
128
129 if matches!(kind, AnnotationKind::Prohibited | AnnotationKind::DeprecationProhibited) {
130 let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
131 self.tcx.emit_node_span_lint(
132 USELESS_DEPRECATED,
133 hir_id,
134 *span,
135 errors::DeprecatedAnnotationHasNoEffect { span: *span },
136 );
137 }
138
139 let depr_entry = DeprecationEntry::local(*depr, def_id);
141 self.index.depr_map.insert(def_id, depr_entry);
142 } else if let Some(parent_depr) = self.parent_depr {
143 if inherit_deprecation.yes() {
144 is_deprecated = true;
145 info!("tagging child {:?} as deprecated from parent", def_id);
146 self.index.depr_map.insert(def_id, parent_depr);
147 }
148 }
149
150 if !self.tcx.features().staged_api() {
151 if let Some(stab) = self.parent_stab {
154 if inherit_deprecation.yes() && stab.is_unstable() {
155 self.index.stab_map.insert(def_id, stab);
156 if fn_sig.is_some_and(|s| s.header.is_const()) {
157 let const_stab =
158 attr::unmarked_crate_const_stab(self.tcx.sess, attrs, stab);
159 self.index.const_stab_map.insert(def_id, const_stab);
160 }
161 }
162 }
163
164 self.recurse_with_stability_attrs(
165 depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
166 None,
167 None,
168 visit_children,
169 );
170 return;
171 }
172
173 let stab = attr::find_stability(self.tcx.sess, attrs, item_sp);
176 let body_stab = attr::find_body_stability(self.tcx.sess, attrs);
177
178 if let Some((depr, span)) = &depr
179 && depr.is_since_rustc_version()
180 && stab.is_none()
181 {
182 self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: *span });
183 }
184
185 if let Some((body_stab, _span)) = body_stab {
186 self.index.default_body_stab_map.insert(def_id, body_stab);
189 debug!(?self.index.default_body_stab_map);
190 }
191
192 let stab = stab.map(|(stab, span)| {
193 if kind == AnnotationKind::Prohibited
195 || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
196 {
197 self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp });
198 }
199
200 debug!("annotate: found {:?}", stab);
201
202 if let (
205 &Some(DeprecatedSince::RustcVersion(dep_since)),
206 &attr::StabilityLevel::Stable { since: stab_since, .. },
207 ) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level)
208 {
209 match stab_since {
210 StableSince::Current => {
211 self.tcx
212 .dcx()
213 .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
214 }
215 StableSince::Version(stab_since) => {
216 if dep_since < stab_since {
217 self.tcx
218 .dcx()
219 .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
220 }
221 }
222 StableSince::Err => {
223 }
226 }
227 }
228
229 if let Stability { level: StabilityLevel::Unstable { .. }, feature } = stab {
232 if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
233 self.tcx
234 .dcx()
235 .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp });
236 }
237 }
238 if let Stability {
239 level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. },
240 feature,
241 } = stab
242 {
243 self.index.implications.insert(implied_by, feature);
244 }
245
246 self.index.stab_map.insert(def_id, stab);
247 stab
248 });
249
250 if stab.is_none() {
251 debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
252 if let Some(stab) = self.parent_stab {
253 if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() {
254 self.index.stab_map.insert(def_id, stab);
255 }
256 }
257 }
258
259 let final_stab = self.index.stab_map.get(&def_id);
260
261 let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item_sp);
264
265 if let Some(fn_sig) = fn_sig
268 && !fn_sig.header.is_const()
269 && const_stab.is_some()
270 {
271 self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
272 }
273
274 if let Some((const_stab, const_span)) = const_stab
276 && let Some(fn_sig) = fn_sig
277 && const_stab.is_const_stable()
278 && !stab.is_some_and(|s| s.is_stable())
279 {
280 self.tcx
281 .dcx()
282 .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
283 }
284
285 if let Some((
288 ConstStability { level: StabilityLevel::Unstable { .. }, feature, .. },
289 const_span,
290 )) = const_stab
291 {
292 if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
293 self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
294 span: const_span,
295 item_sp,
296 });
297 }
298 }
299
300 let mut const_stab = const_stab.map(|(stab, _span)| stab);
303
304 if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() &&
306 let Some(inherit_regular_stab) =
308 final_stab.filter(|s| s.is_unstable())
309 {
310 const_stab = Some(ConstStability {
311 const_stable_indirect: true,
313 promotable: false,
314 level: inherit_regular_stab.level,
315 feature: inherit_regular_stab.feature,
316 });
317 }
318
319 const_stab.inspect(|const_stab| {
321 self.index.const_stab_map.insert(def_id, *const_stab);
322 });
323
324 if let Some(ConstStability {
325 level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. },
326 feature,
327 ..
328 }) = const_stab
329 {
330 self.index.implications.insert(implied_by, feature);
331 }
332
333 if const_stab.is_none() {
338 debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
339 if let Some(parent) = self.parent_const_stab {
340 if parent.is_const_unstable() {
341 self.index.const_stab_map.insert(def_id, parent);
342 }
343 }
344 }
345
346 self.recurse_with_stability_attrs(
347 depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
348 stab,
349 inherit_const_stability.yes().then_some(const_stab).flatten(),
350 visit_children,
351 );
352 }
353
354 fn recurse_with_stability_attrs(
355 &mut self,
356 depr: Option<DeprecationEntry>,
357 stab: Option<Stability>,
358 const_stab: Option<ConstStability>,
359 f: impl FnOnce(&mut Self),
360 ) {
361 let mut replaced_parent_depr = None;
363 let mut replaced_parent_stab = None;
364 let mut replaced_parent_const_stab = None;
365
366 if let Some(depr) = depr {
367 replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
368 }
369 if let Some(stab) = stab {
370 replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
371 }
372 if let Some(const_stab) = const_stab {
373 replaced_parent_const_stab =
374 Some(replace(&mut self.parent_const_stab, Some(const_stab)));
375 }
376
377 f(self);
378
379 if let Some(orig_parent_depr) = replaced_parent_depr {
380 self.parent_depr = orig_parent_depr;
381 }
382 if let Some(orig_parent_stab) = replaced_parent_stab {
383 self.parent_stab = orig_parent_stab;
384 }
385 if let Some(orig_parent_const_stab) = replaced_parent_const_stab {
386 self.parent_const_stab = orig_parent_const_stab;
387 }
388 }
389}
390
391impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
392 type NestedFilter = nested_filter::All;
396
397 fn nested_visit_map(&mut self) -> Self::Map {
398 self.tcx.hir()
399 }
400
401 fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
402 let orig_in_trait_impl = self.in_trait_impl;
403 let mut kind = AnnotationKind::Required;
404 let mut const_stab_inherit = InheritConstStability::No;
405 let mut fn_sig = None;
406
407 match i.kind {
408 hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
413 | hir::ItemKind::ForeignMod { .. } => {
414 self.in_trait_impl = false;
415 kind = AnnotationKind::Container;
416 }
417 hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
418 self.in_trait_impl = true;
419 kind = AnnotationKind::DeprecationProhibited;
420 const_stab_inherit = InheritConstStability::Yes;
421 }
422 hir::ItemKind::Struct(ref sd, _) => {
423 if let Some(ctor_def_id) = sd.ctor_def_id() {
424 self.annotate(
425 ctor_def_id,
426 i.span,
427 None,
428 AnnotationKind::Required,
429 InheritDeprecation::Yes,
430 InheritConstStability::No,
431 InheritStability::Yes,
432 |_| {},
433 )
434 }
435 }
436 hir::ItemKind::Fn { sig: ref item_fn_sig, .. } => {
437 fn_sig = Some(item_fn_sig);
438 }
439 _ => {}
440 }
441
442 self.annotate(
443 i.owner_id.def_id,
444 i.span,
445 fn_sig,
446 kind,
447 InheritDeprecation::Yes,
448 const_stab_inherit,
449 InheritStability::No,
450 |v| intravisit::walk_item(v, i),
451 );
452 self.in_trait_impl = orig_in_trait_impl;
453 }
454
455 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
456 let fn_sig = match ti.kind {
457 hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
458 _ => None,
459 };
460
461 self.annotate(
462 ti.owner_id.def_id,
463 ti.span,
464 fn_sig,
465 AnnotationKind::Required,
466 InheritDeprecation::Yes,
467 InheritConstStability::No,
468 InheritStability::No,
469 |v| {
470 intravisit::walk_trait_item(v, ti);
471 },
472 );
473 }
474
475 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
476 let kind =
477 if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
478
479 let fn_sig = match ii.kind {
480 hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
481 _ => None,
482 };
483
484 self.annotate(
485 ii.owner_id.def_id,
486 ii.span,
487 fn_sig,
488 kind,
489 InheritDeprecation::Yes,
490 InheritConstStability::No,
491 InheritStability::No,
492 |v| {
493 intravisit::walk_impl_item(v, ii);
494 },
495 );
496 }
497
498 fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
499 self.annotate(
500 var.def_id,
501 var.span,
502 None,
503 AnnotationKind::Required,
504 InheritDeprecation::Yes,
505 InheritConstStability::No,
506 InheritStability::Yes,
507 |v| {
508 if let Some(ctor_def_id) = var.data.ctor_def_id() {
509 v.annotate(
510 ctor_def_id,
511 var.span,
512 None,
513 AnnotationKind::Required,
514 InheritDeprecation::Yes,
515 InheritConstStability::No,
516 InheritStability::Yes,
517 |_| {},
518 );
519 }
520
521 intravisit::walk_variant(v, var)
522 },
523 )
524 }
525
526 fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
527 self.annotate(
528 s.def_id,
529 s.span,
530 None,
531 AnnotationKind::Required,
532 InheritDeprecation::Yes,
533 InheritConstStability::No,
534 InheritStability::Yes,
535 |v| {
536 intravisit::walk_field_def(v, s);
537 },
538 );
539 }
540
541 fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
542 let fn_sig = match &i.kind {
543 rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig),
544 _ => None,
545 };
546 self.annotate(
547 i.owner_id.def_id,
548 i.span,
549 fn_sig,
550 AnnotationKind::Required,
551 InheritDeprecation::Yes,
552 InheritConstStability::No,
553 InheritStability::No,
554 |v| {
555 intravisit::walk_foreign_item(v, i);
556 },
557 );
558 }
559
560 fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
561 let kind = match &p.kind {
562 hir::GenericParamKind::Type { default: Some(_), .. }
564 | hir::GenericParamKind::Const { default: Some(_), .. } => AnnotationKind::Container,
565 _ => AnnotationKind::Prohibited,
566 };
567
568 self.annotate(
569 p.def_id,
570 p.span,
571 None,
572 kind,
573 InheritDeprecation::No,
574 InheritConstStability::No,
575 InheritStability::No,
576 |v| {
577 intravisit::walk_generic_param(v, p);
578 },
579 );
580 }
581}
582
583struct MissingStabilityAnnotations<'tcx> {
584 tcx: TyCtxt<'tcx>,
585 effective_visibilities: &'tcx EffectiveVisibilities,
586}
587
588impl<'tcx> MissingStabilityAnnotations<'tcx> {
589 fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
590 let stab = self.tcx.stability().local_stability(def_id);
591 if !self.tcx.sess.is_test_crate()
592 && stab.is_none()
593 && self.effective_visibilities.is_reachable(def_id)
594 {
595 let descr = self.tcx.def_descr(def_id.to_def_id());
596 self.tcx.dcx().emit_err(errors::MissingStabilityAttr { span, descr });
597 }
598 }
599
600 fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
601 let is_const = self.tcx.is_const_fn(def_id.to_def_id())
602 || (self.tcx.def_kind(def_id.to_def_id()) == DefKind::Trait
603 && self.tcx.is_const_trait(def_id.to_def_id()));
604
605 if is_const
607 && self.effective_visibilities.is_reachable(def_id)
608 && self.tcx.lookup_const_stability(def_id).is_none()
609 {
610 let descr = self.tcx.def_descr(def_id.to_def_id());
611 self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr });
612 }
613 }
614}
615
616impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
617 type NestedFilter = nested_filter::OnlyBodies;
618
619 fn nested_visit_map(&mut self) -> Self::Map {
620 self.tcx.hir()
621 }
622
623 fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
624 if !matches!(
629 i.kind,
630 hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
631 | hir::ItemKind::ForeignMod { .. }
632 ) {
633 self.check_missing_stability(i.owner_id.def_id, i.span);
634 }
635
636 self.check_missing_const_stability(i.owner_id.def_id, i.span);
638
639 intravisit::walk_item(self, i)
640 }
641
642 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
643 self.check_missing_stability(ti.owner_id.def_id, ti.span);
644 intravisit::walk_trait_item(self, ti);
645 }
646
647 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
648 let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id());
649 if self.tcx.impl_trait_ref(impl_def_id).is_none() {
650 self.check_missing_stability(ii.owner_id.def_id, ii.span);
651 self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
652 }
653 intravisit::walk_impl_item(self, ii);
654 }
655
656 fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
657 self.check_missing_stability(var.def_id, var.span);
658 if let Some(ctor_def_id) = var.data.ctor_def_id() {
659 self.check_missing_stability(ctor_def_id, var.span);
660 }
661 intravisit::walk_variant(self, var);
662 }
663
664 fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
665 self.check_missing_stability(s.def_id, s.span);
666 intravisit::walk_field_def(self, s);
667 }
668
669 fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
670 self.check_missing_stability(i.owner_id.def_id, i.span);
671 intravisit::walk_foreign_item(self, i);
672 }
673 }
677
678fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
679 let mut index = Index {
680 stab_map: Default::default(),
681 const_stab_map: Default::default(),
682 default_body_stab_map: Default::default(),
683 depr_map: Default::default(),
684 implications: Default::default(),
685 };
686
687 {
688 let mut annotator = Annotator {
689 tcx,
690 index: &mut index,
691 parent_stab: None,
692 parent_const_stab: None,
693 parent_depr: None,
694 in_trait_impl: false,
695 };
696
697 if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
704 let stability = Stability {
705 level: attr::StabilityLevel::Unstable {
706 reason: UnstableReason::Default,
707 issue: NonZero::new(27812),
708 is_soft: false,
709 implied_by: None,
710 },
711 feature: sym::rustc_private,
712 };
713 annotator.parent_stab = Some(stability);
714 }
715
716 annotator.annotate(
717 CRATE_DEF_ID,
718 tcx.hir().span(CRATE_HIR_ID),
719 None,
720 AnnotationKind::Required,
721 InheritDeprecation::Yes,
722 InheritConstStability::No,
723 InheritStability::No,
724 |v| tcx.hir().walk_toplevel_module(v),
725 );
726 }
727 index
728}
729
730fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
733 tcx.hir().visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
734}
735
736pub(crate) fn provide(providers: &mut Providers) {
737 *providers = Providers {
738 check_mod_unstable_api_usage,
739 stability_index,
740 stability_implications: |tcx, _| tcx.stability().implications.clone(),
741 lookup_stability: |tcx, id| tcx.stability().local_stability(id),
742 lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id),
743 lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id),
744 lookup_deprecation_entry: |tcx, id| tcx.stability().local_deprecation_entry(id),
745 ..*providers
746 };
747}
748
749struct Checker<'tcx> {
750 tcx: TyCtxt<'tcx>,
751}
752
753impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
754 type NestedFilter = nested_filter::OnlyBodies;
755
756 fn nested_visit_map(&mut self) -> Self::Map {
760 self.tcx.hir()
761 }
762
763 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
764 match item.kind {
765 hir::ItemKind::ExternCrate(_) => {
766 if item.span.is_dummy() && item.ident.name != sym::std {
769 return;
770 }
771
772 let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else {
773 return;
774 };
775 let def_id = cnum.as_def_id();
776 self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
777 }
778
779 hir::ItemKind::Impl(hir::Impl {
783 of_trait: Some(ref t),
784 self_ty,
785 items,
786 constness,
787 ..
788 }) => {
789 let features = self.tcx.features();
790 if features.staged_api() {
791 let attrs = self.tcx.hir().attrs(item.hir_id());
792 let stab = attr::find_stability(self.tcx.sess, attrs, item.span);
793 let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span);
794
795 if let Some((
800 Stability { level: attr::StabilityLevel::Unstable { .. }, .. },
801 span,
802 )) = stab
803 {
804 let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
805 c.visit_ty_unambig(self_ty);
806 c.visit_trait_ref(t);
807
808 if t.path.res != Res::Err && c.fully_stable {
811 self.tcx.emit_node_span_lint(
812 INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
813 item.hir_id(),
814 span,
815 errors::IneffectiveUnstableImpl,
816 );
817 }
818 }
819
820 if features.const_trait_impl()
823 && self.tcx.is_const_trait_impl(item.owner_id.to_def_id())
824 && const_stab.is_some_and(|(stab, _)| stab.is_const_stable())
825 {
826 self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span });
827 }
828 }
829
830 match constness {
831 rustc_hir::Constness::Const => {
832 if let Some(def_id) = t.trait_def_id() {
833 self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
835 }
836 }
837 rustc_hir::Constness::NotConst => {}
838 }
839
840 for impl_item_ref in *items {
841 let impl_item = self.tcx.associated_item(impl_item_ref.id.owner_id);
842
843 if let Some(def_id) = impl_item.trait_item_def_id {
844 self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
846 }
847 }
848 }
849
850 _ => (),
851 }
852 intravisit::walk_item(self, item);
853 }
854
855 fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) {
856 match t.modifiers.constness {
857 hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) => {
858 if let Some(def_id) = t.trait_ref.trait_def_id() {
859 self.tcx.check_const_stability(def_id, t.trait_ref.path.span, span);
860 }
861 }
862 hir::BoundConstness::Never => {}
863 }
864 intravisit::walk_poly_trait_ref(self, t);
865 }
866
867 fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) {
868 if let Some(def_id) = path.res.opt_def_id() {
869 let method_span = path.segments.last().map(|s| s.ident.span);
870 let item_is_allowed = self.tcx.check_stability_allow_unstable(
871 def_id,
872 Some(id),
873 path.span,
874 method_span,
875 if is_unstable_reexport(self.tcx, id) {
876 AllowUnstable::Yes
877 } else {
878 AllowUnstable::No
879 },
880 );
881
882 if item_is_allowed {
883 let is_allowed_through_unstable_modules: Option<Symbol> =
885 self.tcx.lookup_stability(def_id).and_then(|stab| match stab.level {
886 StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
887 allowed_through_unstable_modules
888 }
889 _ => None,
890 });
891
892 let parents = path.segments.iter().rev().skip(1);
904 for path_segment in parents {
905 if let Some(def_id) = path_segment.res.opt_def_id() {
906 match is_allowed_through_unstable_modules {
907 None => {
908 self.tcx.check_stability_allow_unstable(
912 def_id,
913 None,
914 path.span,
915 None,
916 if is_unstable_reexport(self.tcx, id) {
917 AllowUnstable::Yes
918 } else {
919 AllowUnstable::No
920 },
921 );
922 }
923 Some(deprecation) => {
924 let eval_result = self.tcx.eval_stability_allow_unstable(
927 def_id,
928 None,
929 path.span,
930 None,
931 if is_unstable_reexport(self.tcx, id) {
932 AllowUnstable::Yes
933 } else {
934 AllowUnstable::No
935 },
936 );
937 let is_allowed = matches!(eval_result, EvalResult::Allow);
938 if !is_allowed {
939 if self.tcx.lint_level_at_node(DEPRECATED, id).0
943 == lint::Level::Allow
944 {
945 return;
946 }
947 let def_path =
949 with_no_trimmed_paths!(self.tcx.def_path_str(def_id));
950 let def_kind = self.tcx.def_descr(def_id);
951 let diag = Deprecated {
952 sub: None,
953 kind: def_kind.to_owned(),
954 path: def_path,
955 note: Some(deprecation),
956 since_kind: lint::DeprecatedSinceKind::InEffect,
957 };
958 self.tcx.emit_node_span_lint(
959 DEPRECATED,
960 id,
961 method_span.unwrap_or(path.span),
962 diag,
963 );
964 }
965 }
966 }
967 }
968 }
969 }
970 }
971
972 intravisit::walk_path(self, path)
973 }
974}
975
976fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
980 let Some(owner) = id.as_owner() else {
982 return false;
983 };
984 let def_id = owner.def_id;
985
986 let Some(stab) = tcx.stability().local_stability(def_id) else {
987 return false;
988 };
989
990 if stab.level.is_stable() {
991 return false;
993 }
994
995 if !matches!(tcx.hir().expect_item(def_id).kind, ItemKind::Use(..)) {
997 return false;
998 }
999
1000 true
1001}
1002
1003struct CheckTraitImplStable<'tcx> {
1004 tcx: TyCtxt<'tcx>,
1005 fully_stable: bool,
1006}
1007
1008impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
1009 fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: hir::HirId) {
1010 if let Some(def_id) = path.res.opt_def_id() {
1011 if let Some(stab) = self.tcx.lookup_stability(def_id) {
1012 self.fully_stable &= stab.level.is_stable();
1013 }
1014 }
1015 intravisit::walk_path(self, path)
1016 }
1017
1018 fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
1019 if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
1020 if let Some(stab) = self.tcx.lookup_stability(trait_did) {
1021 self.fully_stable &= stab.level.is_stable();
1022 }
1023 }
1024 intravisit::walk_trait_ref(self, t)
1025 }
1026
1027 fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) {
1028 if let TyKind::Never = t.kind {
1029 self.fully_stable = false;
1030 }
1031 if let TyKind::BareFn(function) = t.kind {
1032 if extern_abi_stability(function.abi).is_err() {
1033 self.fully_stable = false;
1034 }
1035 }
1036 intravisit::walk_ty(self, t)
1037 }
1038
1039 fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
1040 for ty in fd.inputs {
1041 self.visit_ty_unambig(ty)
1042 }
1043 if let hir::FnRetTy::Return(output_ty) = fd.output {
1044 match output_ty.kind {
1045 TyKind::Never => {} _ => self.visit_ty_unambig(output_ty),
1047 }
1048 }
1049 }
1050}
1051
1052pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
1056 let is_staged_api =
1057 tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api();
1058 if is_staged_api {
1059 let effective_visibilities = &tcx.effective_visibilities(());
1060 let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
1061 missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
1062 tcx.hir().walk_toplevel_module(&mut missing);
1063 tcx.hir().visit_all_item_likes_in_crate(&mut missing);
1064 }
1065
1066 let enabled_lang_features = tcx.features().enabled_lang_features();
1067 let mut lang_features = UnordSet::default();
1068 for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features {
1069 if let Some(version) = stable_since {
1070 unnecessary_stable_feature_lint(tcx, *attr_sp, *gate_name, *version);
1072 }
1073 if !lang_features.insert(gate_name) {
1074 tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
1076 }
1077 }
1078
1079 let enabled_lib_features = tcx.features().enabled_lib_features();
1080 let mut remaining_lib_features = FxIndexMap::default();
1081 for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features {
1082 if remaining_lib_features.contains_key(gate_name) {
1083 tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
1085 }
1086 remaining_lib_features.insert(*gate_name, *attr_sp);
1087 }
1088 remaining_lib_features.swap_remove(&sym::libc);
1096 remaining_lib_features.swap_remove(&sym::test);
1097
1098 fn check_features<'tcx>(
1117 tcx: TyCtxt<'tcx>,
1118 remaining_lib_features: &mut FxIndexMap<Symbol, Span>,
1119 remaining_implications: &mut UnordMap<Symbol, Symbol>,
1120 defined_features: &LibFeatures,
1121 all_implications: &UnordMap<Symbol, Symbol>,
1122 ) {
1123 for (feature, since) in defined_features.to_sorted_vec() {
1124 if let FeatureStability::AcceptedSince(since) = since
1125 && let Some(span) = remaining_lib_features.get(&feature)
1126 {
1127 if let Some(implies) = all_implications.get(&feature) {
1129 unnecessary_partially_stable_feature_lint(tcx, *span, feature, *implies, since);
1130 } else {
1131 unnecessary_stable_feature_lint(tcx, *span, feature, since);
1132 }
1133 }
1134 remaining_lib_features.swap_remove(&feature);
1136
1137 remaining_implications.remove(&feature);
1142
1143 if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
1144 break;
1145 }
1146 }
1147 }
1148
1149 let mut remaining_implications = tcx.stability_implications(LOCAL_CRATE).clone();
1151
1152 let local_defined_features = tcx.lib_features(LOCAL_CRATE);
1155 if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() {
1156 let mut all_implications = remaining_implications.clone();
1160 for &cnum in tcx.crates(()) {
1161 all_implications
1162 .extend_unord(tcx.stability_implications(cnum).items().map(|(k, v)| (*k, *v)));
1163 }
1164
1165 check_features(
1166 tcx,
1167 &mut remaining_lib_features,
1168 &mut remaining_implications,
1169 local_defined_features,
1170 &all_implications,
1171 );
1172
1173 for &cnum in tcx.crates(()) {
1174 if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
1175 break;
1176 }
1177 check_features(
1178 tcx,
1179 &mut remaining_lib_features,
1180 &mut remaining_implications,
1181 tcx.lib_features(cnum),
1182 &all_implications,
1183 );
1184 }
1185 }
1186
1187 for (feature, span) in remaining_lib_features {
1188 tcx.dcx().emit_err(errors::UnknownFeature { span, feature });
1189 }
1190
1191 for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() {
1192 let local_defined_features = tcx.lib_features(LOCAL_CRATE);
1193 let span = local_defined_features
1194 .stability
1195 .get(&feature)
1196 .expect("feature that implied another does not exist")
1197 .1;
1198 tcx.dcx().emit_err(errors::ImpliedFeatureNotExist { span, feature, implied_by });
1199 }
1200
1201 }
1204
1205fn unnecessary_partially_stable_feature_lint(
1206 tcx: TyCtxt<'_>,
1207 span: Span,
1208 feature: Symbol,
1209 implies: Symbol,
1210 since: Symbol,
1211) {
1212 tcx.emit_node_span_lint(
1213 lint::builtin::STABLE_FEATURES,
1214 hir::CRATE_HIR_ID,
1215 span,
1216 errors::UnnecessaryPartialStableFeature {
1217 span,
1218 line: tcx.sess.source_map().span_extend_to_line(span),
1219 feature,
1220 since,
1221 implies,
1222 },
1223 );
1224}
1225
1226fn unnecessary_stable_feature_lint(
1227 tcx: TyCtxt<'_>,
1228 span: Span,
1229 feature: Symbol,
1230 mut since: Symbol,
1231) {
1232 if since.as_str() == VERSION_PLACEHOLDER {
1233 since = sym::env_CFG_RELEASE;
1234 }
1235 tcx.emit_node_span_lint(
1236 lint::builtin::STABLE_FEATURES,
1237 hir::CRATE_HIR_ID,
1238 span,
1239 errors::UnnecessaryStableFeature { feature, since },
1240 );
1241}