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, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability, Stability,
10 StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr,
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_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span));
125 let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect);
126
127 let mut is_deprecated = false;
128 if let Some((depr, span)) = &depr {
129 is_deprecated = true;
130
131 if matches!(kind, AnnotationKind::Prohibited | AnnotationKind::DeprecationProhibited) {
132 let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
133 self.tcx.emit_node_span_lint(
134 USELESS_DEPRECATED,
135 hir_id,
136 *span,
137 errors::DeprecatedAnnotationHasNoEffect { span: *span },
138 );
139 }
140
141 let depr_entry = DeprecationEntry::local(*depr, def_id);
143 self.index.depr_map.insert(def_id, depr_entry);
144 } else if let Some(parent_depr) = self.parent_depr {
145 if inherit_deprecation.yes() {
146 is_deprecated = true;
147 info!("tagging child {:?} as deprecated from parent", def_id);
148 self.index.depr_map.insert(def_id, parent_depr);
149 }
150 }
151
152 if !self.tcx.features().staged_api() {
153 if let Some(stab) = self.parent_stab {
156 if inherit_deprecation.yes() && stab.is_unstable() {
157 self.index.stab_map.insert(def_id, stab);
158 if fn_sig.is_some_and(|s| s.header.is_const()) {
159 self.index.const_stab_map.insert(
160 def_id,
161 ConstStability::unmarked(const_stability_indirect, stab),
162 );
163 }
164 }
165 }
166
167 self.recurse_with_stability_attrs(
168 depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
169 None,
170 None,
171 visit_children,
172 );
173 return;
174 }
175
176 let stab = attr::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span));
178 let body_stab =
179 attr::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability);
180
181 if let Some((depr, span)) = &depr
182 && depr.is_since_rustc_version()
183 && stab.is_none()
184 {
185 self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: *span });
186 }
187
188 if let Some(body_stab) = body_stab {
189 self.index.default_body_stab_map.insert(def_id, body_stab);
192 debug!(?self.index.default_body_stab_map);
193 }
194
195 let stab = stab.map(|(stab, span)| {
196 if kind == AnnotationKind::Prohibited
198 || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
199 {
200 self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp });
201 }
202
203 debug!("annotate: found {:?}", stab);
204
205 if let (
208 &Some(DeprecatedSince::RustcVersion(dep_since)),
209 &attr::StabilityLevel::Stable { since: stab_since, .. },
210 ) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level)
211 {
212 match stab_since {
213 StableSince::Current => {
214 self.tcx
215 .dcx()
216 .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
217 }
218 StableSince::Version(stab_since) => {
219 if dep_since < stab_since {
220 self.tcx
221 .dcx()
222 .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
223 }
224 }
225 StableSince::Err => {
226 }
229 }
230 }
231
232 if let Stability { level: StabilityLevel::Unstable { .. }, feature } = stab {
235 if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
236 self.tcx
237 .dcx()
238 .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp });
239 }
240 }
241 if let Stability {
242 level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. },
243 feature,
244 } = stab
245 {
246 self.index.implications.insert(implied_by, feature);
247 }
248
249 self.index.stab_map.insert(def_id, stab);
250 stab
251 });
252
253 if stab.is_none() {
254 debug!("annotate: stab not found, parent = {:?}", self.parent_stab);
255 if let Some(stab) = self.parent_stab {
256 if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() {
257 self.index.stab_map.insert(def_id, stab);
258 }
259 }
260 }
261
262 let final_stab = self.index.stab_map.get(&def_id);
263
264 let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span));
267
268 if let Some(fn_sig) = fn_sig
271 && !fn_sig.header.is_const()
272 && const_stab.is_some()
273 {
274 self.tcx.dcx().emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span });
275 }
276
277 if let Some((const_stab, const_span)) = const_stab
279 && let Some(fn_sig) = fn_sig
280 && const_stab.is_const_stable()
281 && !stab.is_some_and(|s| s.is_stable())
282 {
283 self.tcx
284 .dcx()
285 .emit_err(errors::ConstStableNotStable { fn_sig_span: fn_sig.span, const_span });
286 }
287
288 if let Some((
291 PartialConstStability { level: StabilityLevel::Unstable { .. }, feature, .. },
292 const_span,
293 )) = const_stab
294 {
295 if ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature).is_some() {
296 self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature {
297 span: const_span,
298 item_sp,
299 });
300 }
301 }
302
303 if let Some((stab, span)) = &const_stab
304 && stab.is_const_stable()
305 && const_stability_indirect
306 {
307 self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span: *span });
308 }
309
310 let mut const_stab = const_stab
313 .map(|(stab, _span)| ConstStability::from_partial(stab, const_stability_indirect));
314
315 if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() &&
317 let Some(inherit_regular_stab) =
319 final_stab.filter(|s| s.is_unstable())
320 {
321 const_stab = Some(ConstStability {
322 const_stable_indirect: true,
324 promotable: false,
325 level: inherit_regular_stab.level,
326 feature: inherit_regular_stab.feature,
327 });
328 }
329
330 const_stab.inspect(|const_stab| {
332 self.index.const_stab_map.insert(def_id, *const_stab);
333 });
334
335 if let Some(ConstStability {
336 level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. },
337 feature,
338 ..
339 }) = const_stab
340 {
341 self.index.implications.insert(implied_by, feature);
342 }
343
344 if const_stab.is_none() {
349 debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab);
350 if let Some(parent) = self.parent_const_stab {
351 if parent.is_const_unstable() {
352 self.index.const_stab_map.insert(def_id, parent);
353 }
354 }
355 }
356
357 self.recurse_with_stability_attrs(
358 depr.map(|(d, _)| DeprecationEntry::local(d, def_id)),
359 stab,
360 inherit_const_stability.yes().then_some(const_stab).flatten(),
361 visit_children,
362 );
363 }
364
365 fn recurse_with_stability_attrs(
366 &mut self,
367 depr: Option<DeprecationEntry>,
368 stab: Option<Stability>,
369 const_stab: Option<ConstStability>,
370 f: impl FnOnce(&mut Self),
371 ) {
372 let mut replaced_parent_depr = None;
374 let mut replaced_parent_stab = None;
375 let mut replaced_parent_const_stab = None;
376
377 if let Some(depr) = depr {
378 replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
379 }
380 if let Some(stab) = stab {
381 replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
382 }
383 if let Some(const_stab) = const_stab {
384 replaced_parent_const_stab =
385 Some(replace(&mut self.parent_const_stab, Some(const_stab)));
386 }
387
388 f(self);
389
390 if let Some(orig_parent_depr) = replaced_parent_depr {
391 self.parent_depr = orig_parent_depr;
392 }
393 if let Some(orig_parent_stab) = replaced_parent_stab {
394 self.parent_stab = orig_parent_stab;
395 }
396 if let Some(orig_parent_const_stab) = replaced_parent_const_stab {
397 self.parent_const_stab = orig_parent_const_stab;
398 }
399 }
400}
401
402impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
403 type NestedFilter = nested_filter::All;
407
408 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
409 self.tcx
410 }
411
412 fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
413 let orig_in_trait_impl = self.in_trait_impl;
414 let mut kind = AnnotationKind::Required;
415 let mut const_stab_inherit = InheritConstStability::No;
416 let mut fn_sig = None;
417
418 match i.kind {
419 hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
424 | hir::ItemKind::ForeignMod { .. } => {
425 self.in_trait_impl = false;
426 kind = AnnotationKind::Container;
427 }
428 hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
429 self.in_trait_impl = true;
430 kind = AnnotationKind::DeprecationProhibited;
431 const_stab_inherit = InheritConstStability::Yes;
432 }
433 hir::ItemKind::Struct(ref sd, _) => {
434 if let Some(ctor_def_id) = sd.ctor_def_id() {
435 self.annotate(
436 ctor_def_id,
437 i.span,
438 None,
439 AnnotationKind::Required,
440 InheritDeprecation::Yes,
441 InheritConstStability::No,
442 InheritStability::Yes,
443 |_| {},
444 )
445 }
446 }
447 hir::ItemKind::Fn { sig: ref item_fn_sig, .. } => {
448 fn_sig = Some(item_fn_sig);
449 }
450 _ => {}
451 }
452
453 self.annotate(
454 i.owner_id.def_id,
455 i.span,
456 fn_sig,
457 kind,
458 InheritDeprecation::Yes,
459 const_stab_inherit,
460 InheritStability::No,
461 |v| intravisit::walk_item(v, i),
462 );
463 self.in_trait_impl = orig_in_trait_impl;
464 }
465
466 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
467 let fn_sig = match ti.kind {
468 hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
469 _ => None,
470 };
471
472 self.annotate(
473 ti.owner_id.def_id,
474 ti.span,
475 fn_sig,
476 AnnotationKind::Required,
477 InheritDeprecation::Yes,
478 InheritConstStability::No,
479 InheritStability::No,
480 |v| {
481 intravisit::walk_trait_item(v, ti);
482 },
483 );
484 }
485
486 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
487 let kind =
488 if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
489
490 let fn_sig = match ii.kind {
491 hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig),
492 _ => None,
493 };
494
495 self.annotate(
496 ii.owner_id.def_id,
497 ii.span,
498 fn_sig,
499 kind,
500 InheritDeprecation::Yes,
501 InheritConstStability::No,
502 InheritStability::No,
503 |v| {
504 intravisit::walk_impl_item(v, ii);
505 },
506 );
507 }
508
509 fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
510 self.annotate(
511 var.def_id,
512 var.span,
513 None,
514 AnnotationKind::Required,
515 InheritDeprecation::Yes,
516 InheritConstStability::No,
517 InheritStability::Yes,
518 |v| {
519 if let Some(ctor_def_id) = var.data.ctor_def_id() {
520 v.annotate(
521 ctor_def_id,
522 var.span,
523 None,
524 AnnotationKind::Required,
525 InheritDeprecation::Yes,
526 InheritConstStability::No,
527 InheritStability::Yes,
528 |_| {},
529 );
530 }
531
532 intravisit::walk_variant(v, var)
533 },
534 )
535 }
536
537 fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
538 self.annotate(
539 s.def_id,
540 s.span,
541 None,
542 AnnotationKind::Required,
543 InheritDeprecation::Yes,
544 InheritConstStability::No,
545 InheritStability::Yes,
546 |v| {
547 intravisit::walk_field_def(v, s);
548 },
549 );
550 }
551
552 fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
553 let fn_sig = match &i.kind {
554 rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig),
555 _ => None,
556 };
557 self.annotate(
558 i.owner_id.def_id,
559 i.span,
560 fn_sig,
561 AnnotationKind::Required,
562 InheritDeprecation::Yes,
563 InheritConstStability::No,
564 InheritStability::No,
565 |v| {
566 intravisit::walk_foreign_item(v, i);
567 },
568 );
569 }
570
571 fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
572 let kind = match &p.kind {
573 hir::GenericParamKind::Type { default: Some(_), .. }
575 | hir::GenericParamKind::Const { default: Some(_), .. } => AnnotationKind::Container,
576 _ => AnnotationKind::Prohibited,
577 };
578
579 self.annotate(
580 p.def_id,
581 p.span,
582 None,
583 kind,
584 InheritDeprecation::No,
585 InheritConstStability::No,
586 InheritStability::No,
587 |v| {
588 intravisit::walk_generic_param(v, p);
589 },
590 );
591 }
592}
593
594struct MissingStabilityAnnotations<'tcx> {
595 tcx: TyCtxt<'tcx>,
596 effective_visibilities: &'tcx EffectiveVisibilities,
597}
598
599impl<'tcx> MissingStabilityAnnotations<'tcx> {
600 fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
601 let stab = self.tcx.stability().local_stability(def_id);
602 if !self.tcx.sess.is_test_crate()
603 && stab.is_none()
604 && self.effective_visibilities.is_reachable(def_id)
605 {
606 let descr = self.tcx.def_descr(def_id.to_def_id());
607 self.tcx.dcx().emit_err(errors::MissingStabilityAttr { span, descr });
608 }
609 }
610
611 fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
612 let is_const = self.tcx.is_const_fn(def_id.to_def_id())
613 || (self.tcx.def_kind(def_id.to_def_id()) == DefKind::Trait
614 && self.tcx.is_const_trait(def_id.to_def_id()));
615
616 if is_const
618 && self.effective_visibilities.is_reachable(def_id)
619 && self.tcx.lookup_const_stability(def_id).is_none()
620 {
621 let descr = self.tcx.def_descr(def_id.to_def_id());
622 self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr });
623 }
624 }
625}
626
627impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
628 type NestedFilter = nested_filter::OnlyBodies;
629
630 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
631 self.tcx
632 }
633
634 fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
635 if !matches!(
640 i.kind,
641 hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
642 | hir::ItemKind::ForeignMod { .. }
643 ) {
644 self.check_missing_stability(i.owner_id.def_id, i.span);
645 }
646
647 self.check_missing_const_stability(i.owner_id.def_id, i.span);
649
650 intravisit::walk_item(self, i)
651 }
652
653 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
654 self.check_missing_stability(ti.owner_id.def_id, ti.span);
655 intravisit::walk_trait_item(self, ti);
656 }
657
658 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
659 let impl_def_id = self.tcx.hir_get_parent_item(ii.hir_id());
660 if self.tcx.impl_trait_ref(impl_def_id).is_none() {
661 self.check_missing_stability(ii.owner_id.def_id, ii.span);
662 self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
663 }
664 intravisit::walk_impl_item(self, ii);
665 }
666
667 fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
668 self.check_missing_stability(var.def_id, var.span);
669 if let Some(ctor_def_id) = var.data.ctor_def_id() {
670 self.check_missing_stability(ctor_def_id, var.span);
671 }
672 intravisit::walk_variant(self, var);
673 }
674
675 fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
676 self.check_missing_stability(s.def_id, s.span);
677 intravisit::walk_field_def(self, s);
678 }
679
680 fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
681 self.check_missing_stability(i.owner_id.def_id, i.span);
682 intravisit::walk_foreign_item(self, i);
683 }
684 }
688
689fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
690 let mut index = Index {
691 stab_map: Default::default(),
692 const_stab_map: Default::default(),
693 default_body_stab_map: Default::default(),
694 depr_map: Default::default(),
695 implications: Default::default(),
696 };
697
698 {
699 let mut annotator = Annotator {
700 tcx,
701 index: &mut index,
702 parent_stab: None,
703 parent_const_stab: None,
704 parent_depr: None,
705 in_trait_impl: false,
706 };
707
708 if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
715 let stability = Stability {
716 level: attr::StabilityLevel::Unstable {
717 reason: UnstableReason::Default,
718 issue: NonZero::new(27812),
719 is_soft: false,
720 implied_by: None,
721 },
722 feature: sym::rustc_private,
723 };
724 annotator.parent_stab = Some(stability);
725 }
726
727 annotator.annotate(
728 CRATE_DEF_ID,
729 tcx.hir().span(CRATE_HIR_ID),
730 None,
731 AnnotationKind::Required,
732 InheritDeprecation::Yes,
733 InheritConstStability::No,
734 InheritStability::No,
735 |v| tcx.hir_walk_toplevel_module(v),
736 );
737 }
738 index
739}
740
741fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
744 tcx.hir_visit_item_likes_in_module(module_def_id, &mut Checker { tcx });
745}
746
747pub(crate) fn provide(providers: &mut Providers) {
748 *providers = Providers {
749 check_mod_unstable_api_usage,
750 stability_index,
751 stability_implications: |tcx, _| tcx.stability().implications.clone(),
752 lookup_stability: |tcx, id| tcx.stability().local_stability(id),
753 lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id),
754 lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id),
755 lookup_deprecation_entry: |tcx, id| tcx.stability().local_deprecation_entry(id),
756 ..*providers
757 };
758}
759
760struct Checker<'tcx> {
761 tcx: TyCtxt<'tcx>,
762}
763
764impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
765 type NestedFilter = nested_filter::OnlyBodies;
766
767 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
771 self.tcx
772 }
773
774 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
775 match item.kind {
776 hir::ItemKind::ExternCrate(_) => {
777 if item.span.is_dummy() && item.ident.name != sym::std {
780 return;
781 }
782
783 let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else {
784 return;
785 };
786 let def_id = cnum.as_def_id();
787 self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
788 }
789
790 hir::ItemKind::Impl(hir::Impl {
794 of_trait: Some(t), self_ty, items, constness, ..
795 }) => {
796 let features = self.tcx.features();
797 if features.staged_api() {
798 let attrs = self.tcx.hir_attrs(item.hir_id());
799 let stab = attr::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span));
800
801 let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);
803
804 if let Some((
809 Stability { level: attr::StabilityLevel::Unstable { .. }, .. },
810 span,
811 )) = stab
812 {
813 let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
814 c.visit_ty_unambig(self_ty);
815 c.visit_trait_ref(t);
816
817 if t.path.res != Res::Err && c.fully_stable {
820 self.tcx.emit_node_span_lint(
821 INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
822 item.hir_id(),
823 span,
824 errors::IneffectiveUnstableImpl,
825 );
826 }
827 }
828
829 if features.const_trait_impl()
830 && let hir::Constness::Const = constness
831 {
832 let stable_or_implied_stable = match const_stab {
833 None => true,
834 Some(stab) if stab.is_const_stable() => {
835 self.tcx
839 .dcx()
840 .emit_err(errors::TraitImplConstStable { span: item.span });
841 true
842 }
843 Some(_) => false,
844 };
845
846 if let Some(trait_id) = t.trait_def_id()
847 && let Some(const_stab) = self.tcx.lookup_const_stability(trait_id)
848 {
849 if const_stab.is_const_stable() != stable_or_implied_stable {
851 let trait_span = self.tcx.def_ident_span(trait_id).unwrap();
852
853 let impl_stability = if stable_or_implied_stable {
854 errors::ImplConstStability::Stable { span: item.span }
855 } else {
856 errors::ImplConstStability::Unstable { span: item.span }
857 };
858 let trait_stability = if const_stab.is_const_stable() {
859 errors::TraitConstStability::Stable { span: trait_span }
860 } else {
861 errors::TraitConstStability::Unstable { span: trait_span }
862 };
863
864 self.tcx.dcx().emit_err(errors::TraitImplConstStabilityMismatch {
865 span: item.span,
866 impl_stability,
867 trait_stability,
868 });
869 }
870 }
871 }
872 }
873
874 if let hir::Constness::Const = constness
875 && let Some(def_id) = t.trait_def_id()
876 {
877 self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
879 }
880
881 for impl_item_ref in *items {
882 let impl_item = self.tcx.associated_item(impl_item_ref.id.owner_id);
883
884 if let Some(def_id) = impl_item.trait_item_def_id {
885 self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
887 }
888 }
889 }
890
891 _ => (),
892 }
893 intravisit::walk_item(self, item);
894 }
895
896 fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) {
897 match t.modifiers.constness {
898 hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) => {
899 if let Some(def_id) = t.trait_ref.trait_def_id() {
900 self.tcx.check_const_stability(def_id, t.trait_ref.path.span, span);
901 }
902 }
903 hir::BoundConstness::Never => {}
904 }
905 intravisit::walk_poly_trait_ref(self, t);
906 }
907
908 fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) {
909 if let Some(def_id) = path.res.opt_def_id() {
910 let method_span = path.segments.last().map(|s| s.ident.span);
911 let item_is_allowed = self.tcx.check_stability_allow_unstable(
912 def_id,
913 Some(id),
914 path.span,
915 method_span,
916 if is_unstable_reexport(self.tcx, id) {
917 AllowUnstable::Yes
918 } else {
919 AllowUnstable::No
920 },
921 );
922
923 if item_is_allowed {
924 let is_allowed_through_unstable_modules: Option<Symbol> =
926 self.tcx.lookup_stability(def_id).and_then(|stab| match stab.level {
927 StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
928 allowed_through_unstable_modules
929 }
930 _ => None,
931 });
932
933 let parents = path.segments.iter().rev().skip(1);
945 for path_segment in parents {
946 if let Some(def_id) = path_segment.res.opt_def_id() {
947 match is_allowed_through_unstable_modules {
948 None => {
949 self.tcx.check_stability_allow_unstable(
953 def_id,
954 None,
955 path.span,
956 None,
957 if is_unstable_reexport(self.tcx, id) {
958 AllowUnstable::Yes
959 } else {
960 AllowUnstable::No
961 },
962 );
963 }
964 Some(deprecation) => {
965 let eval_result = self.tcx.eval_stability_allow_unstable(
968 def_id,
969 None,
970 path.span,
971 None,
972 if is_unstable_reexport(self.tcx, id) {
973 AllowUnstable::Yes
974 } else {
975 AllowUnstable::No
976 },
977 );
978 let is_allowed = matches!(eval_result, EvalResult::Allow);
979 if !is_allowed {
980 if self.tcx.lint_level_at_node(DEPRECATED, id).0
984 == lint::Level::Allow
985 {
986 return;
987 }
988 let def_path =
990 with_no_trimmed_paths!(self.tcx.def_path_str(def_id));
991 let def_kind = self.tcx.def_descr(def_id);
992 let diag = Deprecated {
993 sub: None,
994 kind: def_kind.to_owned(),
995 path: def_path,
996 note: Some(deprecation),
997 since_kind: lint::DeprecatedSinceKind::InEffect,
998 };
999 self.tcx.emit_node_span_lint(
1000 DEPRECATED,
1001 id,
1002 method_span.unwrap_or(path.span),
1003 diag,
1004 );
1005 }
1006 }
1007 }
1008 }
1009 }
1010 }
1011 }
1012
1013 intravisit::walk_path(self, path)
1014 }
1015}
1016
1017fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
1021 let Some(owner) = id.as_owner() else {
1023 return false;
1024 };
1025 let def_id = owner.def_id;
1026
1027 let Some(stab) = tcx.stability().local_stability(def_id) else {
1028 return false;
1029 };
1030
1031 if stab.level.is_stable() {
1032 return false;
1034 }
1035
1036 if !matches!(tcx.hir_expect_item(def_id).kind, ItemKind::Use(..)) {
1038 return false;
1039 }
1040
1041 true
1042}
1043
1044struct CheckTraitImplStable<'tcx> {
1045 tcx: TyCtxt<'tcx>,
1046 fully_stable: bool,
1047}
1048
1049impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
1050 fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: hir::HirId) {
1051 if let Some(def_id) = path.res.opt_def_id() {
1052 if let Some(stab) = self.tcx.lookup_stability(def_id) {
1053 self.fully_stable &= stab.level.is_stable();
1054 }
1055 }
1056 intravisit::walk_path(self, path)
1057 }
1058
1059 fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
1060 if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
1061 if let Some(stab) = self.tcx.lookup_stability(trait_did) {
1062 self.fully_stable &= stab.level.is_stable();
1063 }
1064 }
1065 intravisit::walk_trait_ref(self, t)
1066 }
1067
1068 fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) {
1069 if let TyKind::Never = t.kind {
1070 self.fully_stable = false;
1071 }
1072 if let TyKind::BareFn(function) = t.kind {
1073 if extern_abi_stability(function.abi).is_err() {
1074 self.fully_stable = false;
1075 }
1076 }
1077 intravisit::walk_ty(self, t)
1078 }
1079
1080 fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
1081 for ty in fd.inputs {
1082 self.visit_ty_unambig(ty)
1083 }
1084 if let hir::FnRetTy::Return(output_ty) = fd.output {
1085 match output_ty.kind {
1086 TyKind::Never => {} _ => self.visit_ty_unambig(output_ty),
1088 }
1089 }
1090 }
1091}
1092
1093pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
1097 let is_staged_api =
1098 tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api();
1099 if is_staged_api {
1100 let effective_visibilities = &tcx.effective_visibilities(());
1101 let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
1102 missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
1103 tcx.hir_walk_toplevel_module(&mut missing);
1104 tcx.hir_visit_all_item_likes_in_crate(&mut missing);
1105 }
1106
1107 let enabled_lang_features = tcx.features().enabled_lang_features();
1108 let mut lang_features = UnordSet::default();
1109 for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features {
1110 if let Some(version) = stable_since {
1111 unnecessary_stable_feature_lint(tcx, *attr_sp, *gate_name, *version);
1113 }
1114 if !lang_features.insert(gate_name) {
1115 tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
1117 }
1118 }
1119
1120 let enabled_lib_features = tcx.features().enabled_lib_features();
1121 let mut remaining_lib_features = FxIndexMap::default();
1122 for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features {
1123 if remaining_lib_features.contains_key(gate_name) {
1124 tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name });
1126 }
1127 remaining_lib_features.insert(*gate_name, *attr_sp);
1128 }
1129 remaining_lib_features.swap_remove(&sym::libc);
1137 remaining_lib_features.swap_remove(&sym::test);
1138
1139 fn check_features<'tcx>(
1158 tcx: TyCtxt<'tcx>,
1159 remaining_lib_features: &mut FxIndexMap<Symbol, Span>,
1160 remaining_implications: &mut UnordMap<Symbol, Symbol>,
1161 defined_features: &LibFeatures,
1162 all_implications: &UnordMap<Symbol, Symbol>,
1163 ) {
1164 for (feature, since) in defined_features.to_sorted_vec() {
1165 if let FeatureStability::AcceptedSince(since) = since
1166 && let Some(span) = remaining_lib_features.get(&feature)
1167 {
1168 if let Some(implies) = all_implications.get(&feature) {
1170 unnecessary_partially_stable_feature_lint(tcx, *span, feature, *implies, since);
1171 } else {
1172 unnecessary_stable_feature_lint(tcx, *span, feature, since);
1173 }
1174 }
1175 remaining_lib_features.swap_remove(&feature);
1177
1178 remaining_implications.remove(&feature);
1183
1184 if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
1185 break;
1186 }
1187 }
1188 }
1189
1190 let mut remaining_implications = tcx.stability_implications(LOCAL_CRATE).clone();
1192
1193 let local_defined_features = tcx.lib_features(LOCAL_CRATE);
1196 if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() {
1197 let mut all_implications = remaining_implications.clone();
1201 for &cnum in tcx.crates(()) {
1202 all_implications
1203 .extend_unord(tcx.stability_implications(cnum).items().map(|(k, v)| (*k, *v)));
1204 }
1205
1206 check_features(
1207 tcx,
1208 &mut remaining_lib_features,
1209 &mut remaining_implications,
1210 local_defined_features,
1211 &all_implications,
1212 );
1213
1214 for &cnum in tcx.crates(()) {
1215 if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
1216 break;
1217 }
1218 check_features(
1219 tcx,
1220 &mut remaining_lib_features,
1221 &mut remaining_implications,
1222 tcx.lib_features(cnum),
1223 &all_implications,
1224 );
1225 }
1226 }
1227
1228 for (feature, span) in remaining_lib_features {
1229 tcx.dcx().emit_err(errors::UnknownFeature { span, feature });
1230 }
1231
1232 for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() {
1233 let local_defined_features = tcx.lib_features(LOCAL_CRATE);
1234 let span = local_defined_features
1235 .stability
1236 .get(&feature)
1237 .expect("feature that implied another does not exist")
1238 .1;
1239 tcx.dcx().emit_err(errors::ImpliedFeatureNotExist { span, feature, implied_by });
1240 }
1241
1242 }
1245
1246fn unnecessary_partially_stable_feature_lint(
1247 tcx: TyCtxt<'_>,
1248 span: Span,
1249 feature: Symbol,
1250 implies: Symbol,
1251 since: Symbol,
1252) {
1253 tcx.emit_node_span_lint(
1254 lint::builtin::STABLE_FEATURES,
1255 hir::CRATE_HIR_ID,
1256 span,
1257 errors::UnnecessaryPartialStableFeature {
1258 span,
1259 line: tcx.sess.source_map().span_extend_to_line(span),
1260 feature,
1261 since,
1262 implies,
1263 },
1264 );
1265}
1266
1267fn unnecessary_stable_feature_lint(
1268 tcx: TyCtxt<'_>,
1269 span: Span,
1270 feature: Symbol,
1271 mut since: Symbol,
1272) {
1273 if since.as_str() == VERSION_PLACEHOLDER {
1274 since = sym::env_CFG_RELEASE;
1275 }
1276 tcx.emit_node_span_lint(
1277 lint::builtin::STABLE_FEATURES,
1278 hir::CRATE_HIR_ID,
1279 span,
1280 errors::UnnecessaryStableFeature { feature, since },
1281 );
1282}