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