1use std::num::NonZero;
5
6use rustc_ast_lowering::stability::extern_abi_stability;
7use rustc_data_structures::fx::FxIndexMap;
8use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
9use rustc_feature::{EnabledLangFeature, EnabledLibFeature};
10use rustc_hir::attrs::{AttributeKind, DeprecatedSince};
11use rustc_hir::def::{DefKind, Res};
12use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
13use rustc_hir::intravisit::{self, Visitor, VisitorExt};
14use rustc_hir::{
15 self as hir, AmbigArg, ConstStability, DefaultBodyStability, FieldDef, Item, ItemKind,
16 Stability, StabilityLevel, StableSince, TraitRef, Ty, TyKind, UnstableReason,
17 VERSION_PLACEHOLDER, Variant, find_attr,
18};
19use rustc_middle::hir::nested_filter;
20use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
21use rustc_middle::middle::privacy::EffectiveVisibilities;
22use rustc_middle::middle::stability::{AllowUnstable, Deprecated, DeprecationEntry, EvalResult};
23use rustc_middle::query::{LocalCrate, Providers};
24use rustc_middle::ty::TyCtxt;
25use rustc_middle::ty::print::with_no_trimmed_paths;
26use rustc_session::lint;
27use rustc_session::lint::builtin::{DEPRECATED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL};
28use rustc_span::{Span, Symbol, sym};
29use tracing::instrument;
30
31use crate::errors;
32
33#[derive(PartialEq)]
34enum AnnotationKind {
35 Required,
37 Prohibited,
39 DeprecationProhibited,
41 Container,
43}
44
45fn inherit_deprecation(def_kind: DefKind) -> bool {
46 match def_kind {
47 DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => false,
48 _ => true,
49 }
50}
51
52fn inherit_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
53 let def_kind = tcx.def_kind(def_id);
54 match def_kind {
55 DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
56 match tcx.def_kind(tcx.local_parent(def_id)) {
57 DefKind::Impl { of_trait: true } => true,
58 _ => false,
59 }
60 }
61 _ => false,
62 }
63}
64
65fn annotation_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> AnnotationKind {
66 let def_kind = tcx.def_kind(def_id);
67 match def_kind {
68 DefKind::Impl { of_trait: false } | DefKind::ForeignMod => AnnotationKind::Container,
73 DefKind::Impl { of_trait: true } => AnnotationKind::DeprecationProhibited,
74
75 DefKind::TyParam | DefKind::ConstParam => {
77 match &tcx.hir_node_by_def_id(def_id).expect_generic_param().kind {
78 hir::GenericParamKind::Type { default: Some(_), .. }
79 | hir::GenericParamKind::Const { default: Some(_), .. } => {
80 AnnotationKind::Container
81 }
82 _ => AnnotationKind::Prohibited,
83 }
84 }
85
86 DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst => {
88 match tcx.def_kind(tcx.local_parent(def_id)) {
89 DefKind::Impl { of_trait: true } => AnnotationKind::Prohibited,
90 _ => AnnotationKind::Required,
91 }
92 }
93
94 _ => AnnotationKind::Required,
95 }
96}
97
98fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DeprecationEntry> {
99 let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
100 let depr = find_attr!(attrs,
101 AttributeKind::Deprecation { deprecation, span: _ } => *deprecation
102 );
103
104 let Some(depr) = depr else {
105 if inherit_deprecation(tcx.def_kind(def_id)) {
106 let parent_id = tcx.opt_local_parent(def_id)?;
107 let parent_depr = tcx.lookup_deprecation_entry(parent_id)?;
108 return Some(parent_depr);
109 }
110
111 return None;
112 };
113
114 Some(DeprecationEntry::local(depr, def_id))
116}
117
118fn inherit_stability(def_kind: DefKind) -> bool {
119 match def_kind {
120 DefKind::Field | DefKind::Variant | DefKind::Ctor(..) => true,
121 _ => false,
122 }
123}
124
125const FORCE_UNSTABLE: Stability = Stability {
132 level: StabilityLevel::Unstable {
133 reason: UnstableReason::Default,
134 issue: NonZero::new(27812),
135 is_soft: false,
136 implied_by: None,
137 old_name: None,
138 },
139 feature: sym::rustc_private,
140};
141
142#[instrument(level = "debug", skip(tcx))]
143fn lookup_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Stability> {
144 if !tcx.features().staged_api() {
147 if !tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
148 return None;
149 }
150
151 let Some(parent) = tcx.opt_local_parent(def_id) else { return Some(FORCE_UNSTABLE) };
152
153 if inherit_deprecation(tcx.def_kind(def_id)) {
154 let parent = tcx.lookup_stability(parent)?;
155 if parent.is_unstable() {
156 return Some(parent);
157 }
158 }
159
160 return None;
161 }
162
163 let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
165 let stab = find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability);
166
167 if let Some(stab) = stab {
168 return Some(stab);
169 }
170
171 if inherit_deprecation(tcx.def_kind(def_id)) {
172 let Some(parent) = tcx.opt_local_parent(def_id) else {
173 return tcx
174 .sess
175 .opts
176 .unstable_opts
177 .force_unstable_if_unmarked
178 .then_some(FORCE_UNSTABLE);
179 };
180 let parent = tcx.lookup_stability(parent)?;
181 if parent.is_unstable() || inherit_stability(tcx.def_kind(def_id)) {
182 return Some(parent);
183 }
184 }
185
186 None
187}
188
189#[instrument(level = "debug", skip(tcx))]
190fn lookup_default_body_stability(
191 tcx: TyCtxt<'_>,
192 def_id: LocalDefId,
193) -> Option<DefaultBodyStability> {
194 if !tcx.features().staged_api() {
195 return None;
196 }
197
198 let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
199 find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability)
201}
202
203#[instrument(level = "debug", skip(tcx))]
204fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ConstStability> {
205 if !tcx.features().staged_api() {
206 if inherit_deprecation(tcx.def_kind(def_id)) {
209 let parent = tcx.opt_local_parent(def_id)?;
210 let parent_stab = tcx.lookup_stability(parent)?;
211 if parent_stab.is_unstable()
212 && let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig()
213 && fn_sig.header.is_const()
214 {
215 let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
216 let const_stability_indirect =
217 find_attr!(attrs, AttributeKind::ConstStabilityIndirect);
218 return Some(ConstStability::unmarked(const_stability_indirect, parent_stab));
219 }
220 }
221
222 return None;
223 }
224
225 let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id));
226 let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect);
227 let const_stab =
228 find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability);
229
230 let mut const_stab = const_stab
233 .map(|const_stab| ConstStability::from_partial(const_stab, const_stability_indirect));
234
235 if let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig()
238 && fn_sig.header.is_const()
239 && const_stab.is_none()
240 && let Some(inherit_regular_stab) = tcx.lookup_stability(def_id)
242 && inherit_regular_stab.is_unstable()
243 {
244 const_stab = Some(ConstStability {
245 const_stable_indirect: true,
247 promotable: false,
248 level: inherit_regular_stab.level,
249 feature: inherit_regular_stab.feature,
250 });
251 }
252
253 if let Some(const_stab) = const_stab {
254 return Some(const_stab);
255 }
256
257 if inherit_const_stability(tcx, def_id) {
261 let parent = tcx.opt_local_parent(def_id)?;
262 let parent = tcx.lookup_const_stability(parent)?;
263 if parent.is_const_unstable() {
264 return Some(parent);
265 }
266 }
267
268 None
269}
270
271struct Annotator<'tcx> {
273 tcx: TyCtxt<'tcx>,
274 implications: UnordMap<Symbol, Symbol>,
275}
276
277impl<'tcx> Annotator<'tcx> {
278 #[instrument(level = "trace", skip(self))]
282 fn annotate(&mut self, def_id: LocalDefId) {
283 if !self.tcx.features().staged_api() {
284 return;
285 }
286
287 if let Some(stability) = self.tcx.lookup_stability(def_id)
288 && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level
289 {
290 self.implications.insert(implied_by, stability.feature);
291 }
292
293 if let Some(stability) = self.tcx.lookup_const_stability(def_id)
294 && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level
295 {
296 self.implications.insert(implied_by, stability.feature);
297 }
298 }
299}
300
301impl<'tcx> Visitor<'tcx> for Annotator<'tcx> {
302 type NestedFilter = nested_filter::All;
306
307 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
308 self.tcx
309 }
310
311 fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
312 match i.kind {
313 hir::ItemKind::Struct(_, _, ref sd) => {
314 if let Some(ctor_def_id) = sd.ctor_def_id() {
315 self.annotate(ctor_def_id);
316 }
317 }
318 _ => {}
319 }
320
321 self.annotate(i.owner_id.def_id);
322 intravisit::walk_item(self, i)
323 }
324
325 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
326 self.annotate(ti.owner_id.def_id);
327 intravisit::walk_trait_item(self, ti);
328 }
329
330 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
331 self.annotate(ii.owner_id.def_id);
332 intravisit::walk_impl_item(self, ii);
333 }
334
335 fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
336 self.annotate(var.def_id);
337 if let Some(ctor_def_id) = var.data.ctor_def_id() {
338 self.annotate(ctor_def_id);
339 }
340
341 intravisit::walk_variant(self, var)
342 }
343
344 fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
345 self.annotate(s.def_id);
346 intravisit::walk_field_def(self, s);
347 }
348
349 fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
350 self.annotate(i.owner_id.def_id);
351 intravisit::walk_foreign_item(self, i);
352 }
353
354 fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
355 self.annotate(p.def_id);
356 intravisit::walk_generic_param(self, p);
357 }
358}
359
360struct MissingStabilityAnnotations<'tcx> {
361 tcx: TyCtxt<'tcx>,
362 effective_visibilities: &'tcx EffectiveVisibilities,
363}
364
365impl<'tcx> MissingStabilityAnnotations<'tcx> {
366 #[instrument(level = "trace", skip(self))]
368 fn check_compatible_stability(&self, def_id: LocalDefId) {
369 if !self.tcx.features().staged_api() {
370 return;
371 }
372
373 let depr = self.tcx.lookup_deprecation_entry(def_id);
374 let stab = self.tcx.lookup_stability(def_id);
375 let const_stab = self.tcx.lookup_const_stability(def_id);
376
377 macro_rules! find_attr_span {
378 ($name:ident) => {{
379 let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
380 find_attr!(attrs, AttributeKind::$name { span, .. } => *span)
381 }}
382 }
383
384 if stab.is_none()
385 && depr.map_or(false, |d| d.attr.is_since_rustc_version())
386 && let Some(span) = find_attr_span!(Deprecation)
387 {
388 self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span });
389 }
390
391 if let Some(stab) = stab {
392 let kind = annotation_kind(self.tcx, def_id);
394 if kind == AnnotationKind::Prohibited
395 || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some())
396 {
397 if let Some(span) = find_attr_span!(Stability) {
398 let item_sp = self.tcx.def_span(def_id);
399 self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp });
400 }
401 }
402
403 if let Some(depr) = depr
406 && let DeprecatedSince::RustcVersion(dep_since) = depr.attr.since
407 && let StabilityLevel::Stable { since: stab_since, .. } = stab.level
408 && let Some(span) = find_attr_span!(Stability)
409 {
410 let item_sp = self.tcx.def_span(def_id);
411 match stab_since {
412 StableSince::Current => {
413 self.tcx
414 .dcx()
415 .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
416 }
417 StableSince::Version(stab_since) => {
418 if dep_since < stab_since {
419 self.tcx
420 .dcx()
421 .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
422 }
423 }
424 StableSince::Err(_) => {
425 }
428 }
429 }
430 }
431
432 let fn_sig = self.tcx.hir_node_by_def_id(def_id).fn_sig();
435 if let Some(fn_sig) = fn_sig
436 && !fn_sig.header.is_const()
437 && const_stab.is_some()
438 && find_attr_span!(ConstStability).is_some()
439 {
440 self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
441 }
442
443 if let Some(const_stab) = const_stab
445 && let Some(fn_sig) = fn_sig
446 && const_stab.is_const_stable()
447 && !stab.is_some_and(|s| s.is_stable())
448 && let Some(const_span) = find_attr_span!(ConstStability)
449 {
450 self.tcx
451 .dcx()
452 .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
453 }
454
455 if let Some(stab) = &const_stab
456 && stab.is_const_stable()
457 && stab.const_stable_indirect
458 && let Some(span) = find_attr_span!(ConstStability)
459 {
460 self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span });
461 }
462 }
463
464 #[instrument(level = "debug", skip(self))]
465 fn check_missing_stability(&self, def_id: LocalDefId) {
466 let stab = self.tcx.lookup_stability(def_id);
467 self.tcx.ensure_ok().lookup_const_stability(def_id);
468 if !self.tcx.sess.is_test_crate()
469 && stab.is_none()
470 && self.effective_visibilities.is_reachable(def_id)
471 {
472 let descr = self.tcx.def_descr(def_id.to_def_id());
473 let span = self.tcx.def_span(def_id);
474 self.tcx.dcx().emit_err(errors::MissingStabilityAttr { span, descr });
475 }
476 }
477
478 fn check_missing_const_stability(&self, def_id: LocalDefId) {
479 let is_const = self.tcx.is_const_fn(def_id.to_def_id())
480 || (self.tcx.def_kind(def_id.to_def_id()) == DefKind::Trait
481 && self.tcx.is_const_trait(def_id.to_def_id()));
482
483 if is_const
485 && self.effective_visibilities.is_reachable(def_id)
486 && self.tcx.lookup_const_stability(def_id).is_none()
487 {
488 let span = self.tcx.def_span(def_id);
489 let descr = self.tcx.def_descr(def_id.to_def_id());
490 self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr });
491 }
492 }
493}
494
495impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
496 type NestedFilter = nested_filter::OnlyBodies;
497
498 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
499 self.tcx
500 }
501
502 fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
503 self.check_compatible_stability(i.owner_id.def_id);
504
505 if !matches!(
510 i.kind,
511 hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
512 | hir::ItemKind::ForeignMod { .. }
513 ) {
514 self.check_missing_stability(i.owner_id.def_id);
515 }
516
517 self.check_missing_const_stability(i.owner_id.def_id);
519
520 intravisit::walk_item(self, i)
521 }
522
523 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
524 self.check_compatible_stability(ti.owner_id.def_id);
525 self.check_missing_stability(ti.owner_id.def_id);
526 intravisit::walk_trait_item(self, ti);
527 }
528
529 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
530 self.check_compatible_stability(ii.owner_id.def_id);
531 let impl_def_id = self.tcx.hir_get_parent_item(ii.hir_id());
532 if self.tcx.impl_trait_ref(impl_def_id).is_none() {
533 self.check_missing_stability(ii.owner_id.def_id);
534 self.check_missing_const_stability(ii.owner_id.def_id);
535 }
536 intravisit::walk_impl_item(self, ii);
537 }
538
539 fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
540 self.check_compatible_stability(var.def_id);
541 self.check_missing_stability(var.def_id);
542 if let Some(ctor_def_id) = var.data.ctor_def_id() {
543 self.check_missing_stability(ctor_def_id);
544 }
545 intravisit::walk_variant(self, var);
546 }
547
548 fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
549 self.check_compatible_stability(s.def_id);
550 self.check_missing_stability(s.def_id);
551 intravisit::walk_field_def(self, s);
552 }
553
554 fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
555 self.check_compatible_stability(i.owner_id.def_id);
556 self.check_missing_stability(i.owner_id.def_id);
557 intravisit::walk_foreign_item(self, i);
558 }
559
560 fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
561 self.check_compatible_stability(p.def_id);
562 intravisit::walk_generic_param(self, p);
566 }
567}
568
569fn stability_implications(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> UnordMap<Symbol, Symbol> {
570 let mut annotator = Annotator { tcx, implications: Default::default() };
571 annotator.annotate(CRATE_DEF_ID);
572 tcx.hir_walk_toplevel_module(&mut annotator);
573 annotator.implications
574}
575
576fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
579 tcx.hir_visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
580
581 let is_staged_api =
582 tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api();
583 if is_staged_api {
584 let effective_visibilities = &tcx.effective_visibilities(());
585 let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
586 if module_def_id.is_top_level_module() {
587 missing.check_missing_stability(CRATE_DEF_ID);
588 }
589 tcx.hir_visit_item_likes_in_module(module_def_id, &mut missing);
590 }
591
592 if module_def_id.is_top_level_module() {
593 check_unused_or_stable_features(tcx)
594 }
595}
596
597pub(crate) fn provide(providers: &mut Providers) {
598 *providers = Providers {
599 check_mod_unstable_api_usage,
600 stability_implications,
601 lookup_stability,
602 lookup_const_stability,
603 lookup_default_body_stability,
604 lookup_deprecation_entry,
605 ..*providers
606 };
607}
608
609struct Checker<'tcx> {
610 tcx: TyCtxt<'tcx>,
611}
612
613impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
614 type NestedFilter = nested_filter::OnlyBodies;
615
616 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
620 self.tcx
621 }
622
623 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
624 match item.kind {
625 hir::ItemKind::ExternCrate(_, ident) => {
626 if item.span.is_dummy() && ident.name != sym::std {
629 return;
630 }
631
632 let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else {
633 return;
634 };
635 let def_id = cnum.as_def_id();
636 self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
637 }
638
639 hir::ItemKind::Impl(hir::Impl {
643 of_trait: Some(t), self_ty, items, constness, ..
644 }) => {
645 let features = self.tcx.features();
646 if features.staged_api() {
647 let attrs = self.tcx.hir_attrs(item.hir_id());
648 let stab = find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span));
649
650 let const_stab = find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);
652
653 let unstable_feature_stab =
654 find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i)
655 .map(|i| i.as_slice())
656 .unwrap_or_default();
657
658 if let Some((
674 Stability { level: StabilityLevel::Unstable { .. }, feature },
675 span,
676 )) = stab
677 {
678 let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
679 c.visit_ty_unambig(self_ty);
680 c.visit_trait_ref(t);
681
682 let mut unstable_feature_bound_in_effect = false;
685 for (unstable_bound_feat_name, _) in unstable_feature_stab {
686 if *unstable_bound_feat_name == feature {
687 unstable_feature_bound_in_effect = true;
688 }
689 }
690
691 if t.path.res != Res::Err
694 && c.fully_stable
695 && !unstable_feature_bound_in_effect
696 {
697 self.tcx.emit_node_span_lint(
698 INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
699 item.hir_id(),
700 span,
701 errors::IneffectiveUnstableImpl,
702 );
703 }
704 }
705
706 if features.const_trait_impl()
707 && let hir::Constness::Const = constness
708 {
709 let stable_or_implied_stable = match const_stab {
710 None => true,
711 Some(stab) if stab.is_const_stable() => {
712 self.tcx
716 .dcx()
717 .emit_err(errors::TraitImplConstStable { span: item.span });
718 true
719 }
720 Some(_) => false,
721 };
722
723 if let Some(trait_id) = t.trait_def_id()
724 && let Some(const_stab) = self.tcx.lookup_const_stability(trait_id)
725 {
726 if const_stab.is_const_stable() != stable_or_implied_stable {
728 let trait_span = self.tcx.def_ident_span(trait_id).unwrap();
729
730 let impl_stability = if stable_or_implied_stable {
731 errors::ImplConstStability::Stable { span: item.span }
732 } else {
733 errors::ImplConstStability::Unstable { span: item.span }
734 };
735 let trait_stability = if const_stab.is_const_stable() {
736 errors::TraitConstStability::Stable { span: trait_span }
737 } else {
738 errors::TraitConstStability::Unstable { span: trait_span }
739 };
740
741 self.tcx.dcx().emit_err(errors::TraitImplConstStabilityMismatch {
742 span: item.span,
743 impl_stability,
744 trait_stability,
745 });
746 }
747 }
748 }
749 }
750
751 if let hir::Constness::Const = constness
752 && let Some(def_id) = t.trait_def_id()
753 {
754 self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
756 }
757
758 for impl_item_ref in *items {
759 let impl_item = self.tcx.associated_item(impl_item_ref.owner_id);
760
761 if let Some(def_id) = impl_item.trait_item_def_id {
762 self.tcx.check_stability(
764 def_id,
765 None,
766 self.tcx.def_span(impl_item_ref.owner_id),
767 None,
768 );
769 }
770 }
771 }
772
773 _ => (),
774 }
775 intravisit::walk_item(self, item);
776 }
777
778 fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) {
779 match t.modifiers.constness {
780 hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) => {
781 if let Some(def_id) = t.trait_ref.trait_def_id() {
782 self.tcx.check_const_stability(def_id, t.trait_ref.path.span, span);
783 }
784 }
785 hir::BoundConstness::Never => {}
786 }
787 intravisit::walk_poly_trait_ref(self, t);
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 if item_is_allowed {
806 let is_allowed_through_unstable_modules: Option<Symbol> =
808 self.tcx.lookup_stability(def_id).and_then(|stab| match stab.level {
809 StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
810 allowed_through_unstable_modules
811 }
812 _ => None,
813 });
814
815 let parents = path.segments.iter().rev().skip(1);
827 for path_segment in parents {
828 if let Some(def_id) = path_segment.res.opt_def_id() {
829 match is_allowed_through_unstable_modules {
830 None => {
831 self.tcx.check_stability_allow_unstable(
835 def_id,
836 None,
837 path.span,
838 None,
839 if is_unstable_reexport(self.tcx, id) {
840 AllowUnstable::Yes
841 } else {
842 AllowUnstable::No
843 },
844 );
845 }
846 Some(deprecation) => {
847 let eval_result = self.tcx.eval_stability_allow_unstable(
850 def_id,
851 None,
852 path.span,
853 None,
854 if is_unstable_reexport(self.tcx, id) {
855 AllowUnstable::Yes
856 } else {
857 AllowUnstable::No
858 },
859 );
860 let is_allowed = matches!(eval_result, EvalResult::Allow);
861 if !is_allowed {
862 if self.tcx.lint_level_at_node(DEPRECATED, id).level
866 == lint::Level::Allow
867 {
868 return;
869 }
870 let def_path =
872 with_no_trimmed_paths!(self.tcx.def_path_str(def_id));
873 let def_kind = self.tcx.def_descr(def_id);
874 let diag = Deprecated {
875 sub: None,
876 kind: def_kind.to_owned(),
877 path: def_path,
878 note: Some(deprecation),
879 since_kind: lint::DeprecatedSinceKind::InEffect,
880 };
881 self.tcx.emit_node_span_lint(
882 DEPRECATED,
883 id,
884 method_span.unwrap_or(path.span),
885 diag,
886 );
887 }
888 }
889 }
890 }
891 }
892 }
893 }
894
895 intravisit::walk_path(self, path)
896 }
897}
898
899fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
903 let Some(owner) = id.as_owner() else {
905 return false;
906 };
907 let def_id = owner.def_id;
908
909 let Some(stab) = tcx.lookup_stability(def_id) else {
910 return false;
911 };
912
913 if stab.level.is_stable() {
914 return false;
916 }
917
918 if !matches!(tcx.hir_expect_item(def_id).kind, ItemKind::Use(..)) {
920 return false;
921 }
922
923 true
924}
925
926struct CheckTraitImplStable<'tcx> {
927 tcx: TyCtxt<'tcx>,
928 fully_stable: bool,
929}
930
931impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
932 fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: hir::HirId) {
933 if let Some(def_id) = path.res.opt_def_id()
934 && let Some(stab) = self.tcx.lookup_stability(def_id)
935 {
936 self.fully_stable &= stab.level.is_stable();
937 }
938 intravisit::walk_path(self, path)
939 }
940
941 fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
942 if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
943 if let Some(stab) = self.tcx.lookup_stability(trait_did) {
944 self.fully_stable &= stab.level.is_stable();
945 }
946 }
947 intravisit::walk_trait_ref(self, t)
948 }
949
950 fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) {
951 if let TyKind::Never = t.kind {
952 self.fully_stable = false;
953 }
954 if let TyKind::FnPtr(function) = t.kind {
955 if extern_abi_stability(function.abi).is_err() {
956 self.fully_stable = false;
957 }
958 }
959 intravisit::walk_ty(self, t)
960 }
961
962 fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
963 for ty in fd.inputs {
964 self.visit_ty_unambig(ty)
965 }
966 if let hir::FnRetTy::Return(output_ty) = fd.output {
967 match output_ty.kind {
968 TyKind::Never => {} _ => self.visit_ty_unambig(output_ty),
970 }
971 }
972 }
973}
974
975pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
980 let _prof_timer = tcx.sess.timer("unused_lib_feature_checking");
981
982 let enabled_lang_features = tcx.features().enabled_lang_features();
983 let mut lang_features = UnordSet::default();
984 for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features {
985 if let Some(version) = stable_since {
986 unnecessary_stable_feature_lint(tcx, *attr_sp, *gate_name, *version);
988 }
989 if !lang_features.insert(gate_name) {
990 tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
992 }
993 }
994
995 let enabled_lib_features = tcx.features().enabled_lib_features();
996 let mut remaining_lib_features = FxIndexMap::default();
997 for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features {
998 if remaining_lib_features.contains_key(gate_name) {
999 tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
1001 }
1002 remaining_lib_features.insert(*gate_name, *attr_sp);
1003 }
1004 remaining_lib_features.swap_remove(&sym::libc);
1012 remaining_lib_features.swap_remove(&sym::test);
1013
1014 fn check_features<'tcx>(
1033 tcx: TyCtxt<'tcx>,
1034 remaining_lib_features: &mut FxIndexMap<Symbol, Span>,
1035 remaining_implications: &mut UnordMap<Symbol, Symbol>,
1036 defined_features: &LibFeatures,
1037 all_implications: &UnordMap<Symbol, Symbol>,
1038 ) {
1039 for (feature, stability) in defined_features.to_sorted_vec() {
1040 if let FeatureStability::AcceptedSince(since) = stability
1041 && let Some(span) = remaining_lib_features.get(&feature)
1042 {
1043 if let Some(implies) = all_implications.get(&feature) {
1045 unnecessary_partially_stable_feature_lint(tcx, *span, feature, *implies, since);
1046 } else {
1047 unnecessary_stable_feature_lint(tcx, *span, feature, since);
1048 }
1049 }
1050 remaining_lib_features.swap_remove(&feature);
1052
1053 remaining_implications.remove(&feature);
1058
1059 if let FeatureStability::Unstable { old_name: Some(alias) } = stability
1060 && let Some(span) = remaining_lib_features.swap_remove(&alias)
1061 {
1062 tcx.dcx().emit_err(errors::RenamedFeature { span, feature, alias });
1063 }
1064
1065 if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
1066 break;
1067 }
1068 }
1069 }
1070
1071 let mut remaining_implications = tcx.stability_implications(LOCAL_CRATE).clone();
1073
1074 let local_defined_features = tcx.lib_features(LOCAL_CRATE);
1077 if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() {
1078 let mut all_implications = remaining_implications.clone();
1082 for &cnum in tcx.crates(()) {
1083 all_implications
1084 .extend_unord(tcx.stability_implications(cnum).items().map(|(k, v)| (*k, *v)));
1085 }
1086
1087 check_features(
1088 tcx,
1089 &mut remaining_lib_features,
1090 &mut remaining_implications,
1091 local_defined_features,
1092 &all_implications,
1093 );
1094
1095 for &cnum in tcx.crates(()) {
1096 if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
1097 break;
1098 }
1099 check_features(
1100 tcx,
1101 &mut remaining_lib_features,
1102 &mut remaining_implications,
1103 tcx.lib_features(cnum),
1104 &all_implications,
1105 );
1106 }
1107 }
1108
1109 for (feature, span) in remaining_lib_features {
1110 tcx.dcx().emit_err(errors::UnknownFeature { span, feature });
1111 }
1112
1113 for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() {
1114 let local_defined_features = tcx.lib_features(LOCAL_CRATE);
1115 let span = local_defined_features
1116 .stability
1117 .get(&feature)
1118 .expect("feature that implied another does not exist")
1119 .1;
1120 tcx.dcx().emit_err(errors::ImpliedFeatureNotExist { span, feature, implied_by });
1121 }
1122
1123 }
1126
1127fn unnecessary_partially_stable_feature_lint(
1128 tcx: TyCtxt<'_>,
1129 span: Span,
1130 feature: Symbol,
1131 implies: Symbol,
1132 since: Symbol,
1133) {
1134 tcx.emit_node_span_lint(
1135 lint::builtin::STABLE_FEATURES,
1136 hir::CRATE_HIR_ID,
1137 span,
1138 errors::UnnecessaryPartialStableFeature {
1139 span,
1140 line: tcx.sess.source_map().span_extend_to_line(span),
1141 feature,
1142 since,
1143 implies,
1144 },
1145 );
1146}
1147
1148fn unnecessary_stable_feature_lint(
1149 tcx: TyCtxt<'_>,
1150 span: Span,
1151 feature: Symbol,
1152 mut since: Symbol,
1153) {
1154 if since.as_str() == VERSION_PLACEHOLDER {
1155 since = sym::env_CFG_RELEASE;
1156 }
1157 tcx.emit_node_span_lint(
1158 lint::builtin::STABLE_FEATURES,
1159 hir::CRATE_HIR_ID,
1160 span,
1161 errors::UnnecessaryStableFeature { feature, since },
1162 );
1163}