Skip to main content

rustc_passes/
stability.rs

1//! A pass that annotates every item and method with its stability level,
2//! propagating default levels lexically from parent to children ast nodes.
3
4use 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, UNSTABLE_LANG_FEATURES};
10use rustc_hir::attrs::{AttributeKind, DeprecatedSince};
11use rustc_hir::def::{DefKind, Res};
12use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModId};
13use rustc_hir::intravisit::{self, Visitor};
14use rustc_hir::{
15    self as hir, AmbigArg, ConstStability, Constness, DefaultBodyStability, FieldDef, HirId, Item,
16    ItemKind, Path, Stability, StabilityLevel, StableSince, TraitRef, Ty, TyKind, UnstableReason,
17    UsePath, VERSION_PLACEHOLDER, Variant, find_attr,
18};
19use rustc_lint_defs::builtin::{
20    DEPRECATED, DUPLICATE_FEATURES, INEFFECTIVE_UNSTABLE_REEXPORTS,
21    INEFFECTIVE_UNSTABLE_TRAIT_IMPL, STABLE_FEATURES,
22};
23use rustc_middle::hir::nested_filter;
24use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
25use rustc_middle::middle::privacy::EffectiveVisibilities;
26use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, EvalResult};
27use rustc_middle::query::{LocalCrate, Providers};
28use rustc_middle::ty::{AssocContainer, TyCtxt};
29use rustc_span::{Span, Symbol, span_bug, sym};
30use tracing::instrument;
31
32use crate::diagnostics;
33
34#[derive(#[automatically_derived]
impl ::core::marker::StructuralPartialEq for AnnotationKind { }
#[automatically_derived]
impl ::core::cmp::PartialEq for AnnotationKind {
    #[inline]
    fn eq(&self, other: &AnnotationKind) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq)]
35enum AnnotationKind {
36    /// Annotation is required if not inherited from unstable parents.
37    Required,
38    /// Annotation is useless, reject it.
39    Prohibited,
40    /// Deprecation annotation is useless, reject it. (Stability attribute is still required.)
41    DeprecationProhibited,
42    /// Annotation itself is useless, but it can be propagated to children.
43    Container,
44}
45
46fn inherit_deprecation(def_kind: DefKind) -> bool {
47    match def_kind {
48        DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => false,
49        _ => true,
50    }
51}
52
53fn inherit_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
54    let def_kind = tcx.def_kind(def_id);
55    match def_kind {
56        DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
57            match tcx.def_kind(tcx.local_parent(def_id)) {
58                DefKind::Trait | DefKind::Impl { .. } => true,
59                _ => false,
60            }
61        }
62        DefKind::Closure => true,
63        _ => false,
64    }
65}
66
67fn annotation_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> AnnotationKind {
68    let def_kind = tcx.def_kind(def_id);
69    match def_kind {
70        // Inherent impls and foreign modules serve only as containers for other items,
71        // they don't have their own stability. They still can be annotated as unstable
72        // and propagate this unstability to children, but this annotation is completely
73        // optional. They inherit stability from their parents when unannotated.
74        DefKind::Impl { of_trait: false } | DefKind::ForeignMod => AnnotationKind::Container,
75        DefKind::Impl { of_trait: true } => AnnotationKind::DeprecationProhibited,
76
77        // Allow stability attributes on default generic arguments.
78        DefKind::TyParam | DefKind::ConstParam => {
79            match &tcx.hir_node_by_def_id(def_id).expect_generic_param().kind {
80                hir::GenericParamKind::Type { default: Some(_), .. }
81                | hir::GenericParamKind::Const { default: Some(_), .. } => {
82                    AnnotationKind::Container
83                }
84                _ => AnnotationKind::Prohibited,
85            }
86        }
87
88        // Impl items in trait impls cannot have stability.
89        DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst => {
90            match tcx.def_kind(tcx.local_parent(def_id)) {
91                DefKind::Impl { of_trait: true } => AnnotationKind::Prohibited,
92                _ => AnnotationKind::Required,
93            }
94        }
95
96        _ => AnnotationKind::Required,
97    }
98}
99
100fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DeprecationEntry> {
101    let depr = {
    {
        'done:
            {
            for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &tcx) {
                #[allow(unused_imports)]
                use ::rustc_attr_ir::AttributeKind::*;
                let i: &::rustc_attr_ir::Attribute = i;
                match i {
                    ::rustc_attr_ir::Attribute::Parsed(Deprecated {
                        deprecation, span: _ }) => {
                        break 'done Some(*deprecation);
                    }
                    ::rustc_attr_ir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, def_id,
102        Deprecated { deprecation, span: _ } => *deprecation
103    );
104
105    let Some(depr) = depr else {
106        if inherit_deprecation(tcx.def_kind(def_id)) {
107            let parent_id = tcx.opt_local_parent(def_id)?;
108            let parent_depr = tcx.lookup_deprecation_entry(parent_id)?;
109            return Some(parent_depr);
110        }
111
112        return None;
113    };
114
115    // `Deprecation` is just two pointers, no need to intern it
116    Some(DeprecationEntry::local(depr, def_id))
117}
118
119fn inherit_stability(def_kind: DefKind) -> bool {
120    match def_kind {
121        DefKind::Field | DefKind::Variant | DefKind::Ctor(..) => true,
122        _ => false,
123    }
124}
125
126/// If the `-Z force-unstable-if-unmarked` flag is passed then we provide
127/// a parent stability annotation which indicates that this is private
128/// with the `rustc_private` feature. This is intended for use when
129/// compiling library and `rustc_*` crates themselves so we can leverage crates.io
130/// while maintaining the invariant that all sysroot crates are unstable
131/// by default and are unable to be used.
132const FORCE_UNSTABLE: Stability = Stability {
133    level: StabilityLevel::Unstable {
134        reason: UnstableReason::Default,
135        issue: NonZero::new(27812),
136        implied_by: None,
137        old_name: None,
138    },
139    feature: sym::rustc_private,
140};
141
142{}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("lookup_stability",
                                    "rustc_passes::stability", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_passes/src/stability.rs"),
                                    ::tracing_core::__macro_support::Option::Some(142u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_passes::stability"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("def_id")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("def_id");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&def_id)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: Option<Stability> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if !tcx.features().staged_api() {
                if !tcx.sess.opts.unstable_opts.force_unstable_if_unmarked {
                    return None;
                }
                let Some(parent) =
                    tcx.opt_local_parent(def_id) else {
                        return Some(FORCE_UNSTABLE)
                    };
                if inherit_deprecation(tcx.def_kind(def_id)) {
                    let parent = tcx.lookup_stability(parent)?;
                    if parent.is_unstable() { return Some(parent); }
                }
                return None;
            }
            let stab =
                {
                    {
                        'done:
                            {
                            for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &tcx)
                                {
                                #[allow(unused_imports)]
                                use ::rustc_attr_ir::AttributeKind::*;
                                let i: &::rustc_attr_ir::Attribute = i;
                                match i {
                                    ::rustc_attr_ir::Attribute::Parsed(Stability {
                                        stability, span: _ }) => {
                                        break 'done Some(*stability);
                                    }
                                    ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                        {}
                                        #[deny(unreachable_patterns)]
                                        _ => {}
                                }
                            }
                            None
                        }
                    }
                };
            if let Some(stab) = stab { return Some(stab); }
            if inherit_deprecation(tcx.def_kind(def_id)) {
                let Some(parent) =
                    tcx.opt_local_parent(def_id) else {
                        return tcx.sess.opts.unstable_opts.force_unstable_if_unmarked.then_some(FORCE_UNSTABLE);
                    };
                let parent = tcx.lookup_stability(parent)?;
                if parent.is_unstable() ||
                        inherit_stability(tcx.def_kind(def_id)) {
                    return Some(parent);
                }
            }
            None
        }
    }
}#[instrument(level = "debug", skip(tcx))]
143fn lookup_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<Stability> {
144    // Propagate unstability. This can happen even for non-staged-api crates in case
145    // -Zforce-unstable-if-unmarked is set.
146    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    // # Regular stability
164    let stab = find_attr!(tcx, def_id, Stability { stability, span: _ } => *stability);
165
166    if let Some(stab) = stab {
167        return Some(stab);
168    }
169
170    if inherit_deprecation(tcx.def_kind(def_id)) {
171        let Some(parent) = tcx.opt_local_parent(def_id) else {
172            return tcx
173                .sess
174                .opts
175                .unstable_opts
176                .force_unstable_if_unmarked
177                .then_some(FORCE_UNSTABLE);
178        };
179        let parent = tcx.lookup_stability(parent)?;
180        if parent.is_unstable() || inherit_stability(tcx.def_kind(def_id)) {
181            return Some(parent);
182        }
183    }
184
185    None
186}
187
188{}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("lookup_default_body_stability",
                                    "rustc_passes::stability", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_passes/src/stability.rs"),
                                    ::tracing_core::__macro_support::Option::Some(188u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_passes::stability"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("def_id")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("def_id");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&def_id)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: Option<DefaultBodyStability> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            if !tcx.features().staged_api() { return None; }
            {
                {
                    'done:
                        {
                        for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &tcx)
                            {
                            #[allow(unused_imports)]
                            use ::rustc_attr_ir::AttributeKind::*;
                            let i: &::rustc_attr_ir::Attribute = i;
                            match i {
                                ::rustc_attr_ir::Attribute::Parsed(RustcBodyStability {
                                    stability, .. }) => {
                                    break 'done Some(*stability);
                                }
                                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                    {}
                                    #[deny(unreachable_patterns)]
                                    _ => {}
                            }
                        }
                        None
                    }
                }
            }
        }
    }
}#[instrument(level = "debug", skip(tcx))]
189fn lookup_default_body_stability(
190    tcx: TyCtxt<'_>,
191    def_id: LocalDefId,
192) -> Option<DefaultBodyStability> {
193    if !tcx.features().staged_api() {
194        return None;
195    }
196
197    // FIXME: check that this item can have body stability
198    find_attr!(tcx, def_id, RustcBodyStability { stability, .. } => *stability)
199}
200
201{}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("lookup_const_stability",
                                    "rustc_passes::stability", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_passes/src/stability.rs"),
                                    ::tracing_core::__macro_support::Option::Some(201u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_passes::stability"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("def_id")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("def_id");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&def_id)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: Option<ConstStability> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if !tcx.features().staged_api() {
                if inherit_deprecation(tcx.def_kind(def_id)) {
                    let parent = tcx.opt_local_parent(def_id)?;
                    let parent_stab = tcx.lookup_stability(parent)?;
                    if parent_stab.is_unstable() &&
                                let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig()
                            &&
                            #[allow(non_exhaustive_omitted_patterns)] match fn_sig.header.constness
                                {
                                Constness::Const { .. } => true,
                                _ => false,
                            } {
                        let const_stable_indirect =
                            {
                                    {
                                        'done:
                                            {
                                            for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &tcx)
                                                {
                                                #[allow(unused_imports)]
                                                use ::rustc_attr_ir::AttributeKind::*;
                                                let i: &::rustc_attr_ir::Attribute = i;
                                                match i {
                                                    ::rustc_attr_ir::Attribute::Parsed(RustcConstStableIndirect)
                                                        => {
                                                        break 'done Some(());
                                                    }
                                                    ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                                        {}
                                                        #[deny(unreachable_patterns)]
                                                        _ => {}
                                                }
                                            }
                                            None
                                        }
                                    }
                                }.is_some();
                        return Some(ConstStability::unmarked(const_stable_indirect,
                                    parent_stab));
                    }
                }
                return None;
            }
            let const_stable_indirect =
                {
                        {
                            'done:
                                {
                                for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &tcx)
                                    {
                                    #[allow(unused_imports)]
                                    use ::rustc_attr_ir::AttributeKind::*;
                                    let i: &::rustc_attr_ir::Attribute = i;
                                    match i {
                                        ::rustc_attr_ir::Attribute::Parsed(RustcConstStableIndirect)
                                            => {
                                            break 'done Some(());
                                        }
                                        ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                            {}
                                            #[deny(unreachable_patterns)]
                                            _ => {}
                                    }
                                }
                                None
                            }
                        }
                    }.is_some();
            let const_stab =
                {
                    {
                        'done:
                            {
                            for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &tcx)
                                {
                                #[allow(unused_imports)]
                                use ::rustc_attr_ir::AttributeKind::*;
                                let i: &::rustc_attr_ir::Attribute = i;
                                match i {
                                    ::rustc_attr_ir::Attribute::Parsed(RustcConstStability {
                                        stability, span: _ }) => {
                                        break 'done Some(*stability);
                                    }
                                    ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                        {}
                                        #[deny(unreachable_patterns)]
                                        _ => {}
                                }
                            }
                            None
                        }
                    }
                };
            let mut const_stab =
                const_stab.map(|const_stab|
                        ConstStability::from_partial(const_stab,
                            const_stable_indirect));
            if let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig() &&
                                #[allow(non_exhaustive_omitted_patterns)] match fn_sig.header.constness
                                    {
                                    Constness::Const { .. } => true,
                                    _ => false,
                                } && const_stab.is_none() &&
                        let Some(inherit_regular_stab) =
                            tcx.lookup_stability(def_id) &&
                    inherit_regular_stab.is_unstable() {
                const_stab =
                    Some(ConstStability {
                            const_stable_indirect: true,
                            promotable: false,
                            level: inherit_regular_stab.level,
                            feature: inherit_regular_stab.feature,
                        });
            }
            if let Some(const_stab) = const_stab { return Some(const_stab); }
            if inherit_const_stability(tcx, def_id) {
                let parent = tcx.opt_local_parent(def_id)?;
                let parent = tcx.lookup_const_stability(parent)?;
                if parent.is_const_unstable() { return Some(parent); }
            }
            None
        }
    }
}#[instrument(level = "debug", skip(tcx))]
202fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ConstStability> {
203    if !tcx.features().staged_api() {
204        // Propagate unstability. This can happen even for non-staged-api crates in case
205        // -Zforce-unstable-if-unmarked is set.
206        if inherit_deprecation(tcx.def_kind(def_id)) {
207            let parent = tcx.opt_local_parent(def_id)?;
208            let parent_stab = tcx.lookup_stability(parent)?;
209            if parent_stab.is_unstable()
210                && let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig()
211                && matches!(fn_sig.header.constness, Constness::Const { .. })
212            {
213                let const_stable_indirect = find_attr!(tcx, def_id, RustcConstStableIndirect);
214                return Some(ConstStability::unmarked(const_stable_indirect, parent_stab));
215            }
216        }
217
218        return None;
219    }
220
221    let const_stable_indirect = find_attr!(tcx, def_id, RustcConstStableIndirect);
222    let const_stab =
223        find_attr!(tcx, def_id, RustcConstStability { stability, span: _ } => *stability);
224
225    // After checking the immediate attributes, get rid of the span and compute implied
226    // const stability: inherit feature gate from regular stability.
227    let mut const_stab = const_stab
228        .map(|const_stab| ConstStability::from_partial(const_stab, const_stable_indirect));
229
230    // If this is a const fn but not annotated with stability markers, see if we can inherit
231    // regular stability.
232    if let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig()
233        && matches!(fn_sig.header.constness, Constness::Const { .. })
234        && const_stab.is_none()
235        // We only ever inherit unstable features.
236        && let Some(inherit_regular_stab) = tcx.lookup_stability(def_id)
237        && inherit_regular_stab.is_unstable()
238    {
239        const_stab = Some(ConstStability {
240            // We subject these implicitly-const functions to recursive const stability.
241            const_stable_indirect: true,
242            promotable: false,
243            level: inherit_regular_stab.level,
244            feature: inherit_regular_stab.feature,
245        });
246    }
247
248    if let Some(const_stab) = const_stab {
249        return Some(const_stab);
250    }
251
252    // `impl const Trait for Type` items forward their const stability to their immediate children.
253    // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`?
254    // Currently, once that is set, we do not inherit anything from the parent any more.
255    if inherit_const_stability(tcx, def_id) {
256        let parent = tcx.opt_local_parent(def_id)?;
257        let parent = tcx.lookup_const_stability(parent)?;
258        if parent.is_const_unstable() {
259            return Some(parent);
260        }
261    }
262
263    None
264}
265
266fn stability_implications(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> UnordMap<Symbol, Symbol> {
267    let mut implications = UnordMap::default();
268
269    let mut register_implication = |def_id| {
270        if let Some(stability) = tcx.lookup_stability(def_id)
271            && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level
272        {
273            implications.insert(implied_by, stability.feature);
274        }
275
276        if let Some(stability) = tcx.lookup_const_stability(def_id)
277            && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level
278        {
279            implications.insert(implied_by, stability.feature);
280        }
281    };
282
283    if tcx.features().staged_api() {
284        register_implication(CRATE_DEF_ID);
285        for def_id in tcx.hir_crate_items(()).definitions() {
286            register_implication(def_id);
287            let def_kind = tcx.def_kind(def_id);
288            if def_kind.is_adt() {
289                let adt = tcx.adt_def(def_id);
290                for variant in adt.variants() {
291                    if variant.def_id != def_id.to_def_id() {
292                        register_implication(variant.def_id.expect_local());
293                    }
294                    for field in &variant.fields {
295                        register_implication(field.did.expect_local());
296                    }
297                    if let Some(ctor_def_id) = variant.ctor_def_id() {
298                        register_implication(ctor_def_id.expect_local())
299                    }
300                }
301            }
302            if def_kind.has_generics() {
303                for param in tcx.generics_of(def_id).own_params.iter() {
304                    register_implication(param.def_id.expect_local())
305                }
306            }
307        }
308    }
309
310    implications
311}
312
313struct MissingStabilityAnnotations<'tcx> {
314    tcx: TyCtxt<'tcx>,
315    effective_visibilities: &'tcx EffectiveVisibilities,
316}
317
318impl<'tcx> MissingStabilityAnnotations<'tcx> {
319    /// Verify that deprecation and stability attributes make sense with one another.
320    {}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("check_compatible_stability",
                                    "rustc_passes::stability", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_passes/src/stability.rs"),
                                    ::tracing_core::__macro_support::Option::Some(320u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_passes::stability"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("def_id")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("def_id");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&def_id)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if !self.tcx.features().staged_api() { return; }
            let depr = self.tcx.lookup_deprecation_entry(def_id);
            let stab = self.tcx.lookup_stability(def_id);
            let const_stab = self.tcx.lookup_const_stability(def_id);
            macro_rules! find_attr_span {
                ($name:ident) =>
                {{
                        let attrs =
                        self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
                        find_attr!(attrs, AttributeKind::$name { span, .. } =>
                        *span)
                    }}
            }
            if stab.is_none() &&
                        depr.map_or(false, |d| d.attr.is_since_rustc_version()) &&
                    let Some(span) =
                        {
                            let attrs =
                                self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
                            {
                                'done:
                                    {
                                    for i in attrs {
                                        #[allow(unused_imports)]
                                        use ::rustc_attr_ir::AttributeKind::*;
                                        let i: &::rustc_attr_ir::Attribute = i;
                                        match i {
                                            ::rustc_attr_ir::Attribute::Parsed(AttributeKind::Deprecated {
                                                span, .. }) => {
                                                break 'done Some(*span);
                                            }
                                            ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                                {}
                                                #[deny(unreachable_patterns)]
                                                _ => {}
                                        }
                                    }
                                    None
                                }
                            }
                        } {
                self.tcx.dcx().emit_err(diagnostics::DeprecatedAttribute {
                        span,
                    });
            }
            if let Some(stab) = stab {
                let kind = annotation_kind(self.tcx, def_id);
                if kind == AnnotationKind::Prohibited ||
                        (kind == AnnotationKind::Container && stab.level.is_stable()
                                && depr.is_some()) {
                    if let Some(span) =
                            {
                                let attrs =
                                    self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
                                {
                                    'done:
                                        {
                                        for i in attrs {
                                            #[allow(unused_imports)]
                                            use ::rustc_attr_ir::AttributeKind::*;
                                            let i: &::rustc_attr_ir::Attribute = i;
                                            match i {
                                                ::rustc_attr_ir::Attribute::Parsed(AttributeKind::Stability {
                                                    span, .. }) => {
                                                    break 'done Some(*span);
                                                }
                                                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                                    {}
                                                    #[deny(unreachable_patterns)]
                                                    _ => {}
                                            }
                                        }
                                        None
                                    }
                                }
                            } {
                        let item_sp = self.tcx.def_span(def_id);
                        self.tcx.dcx().emit_err(diagnostics::UselessStability {
                                span,
                                item_sp,
                            });
                    }
                }
                if let Some(depr) = depr &&
                                let DeprecatedSince::RustcVersion(dep_since) =
                                    depr.attr.since &&
                            let StabilityLevel::Stable { since: stab_since, .. } =
                                stab.level &&
                        let Some(span) =
                            {
                                let attrs =
                                    self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
                                {
                                    'done:
                                        {
                                        for i in attrs {
                                            #[allow(unused_imports)]
                                            use ::rustc_attr_ir::AttributeKind::*;
                                            let i: &::rustc_attr_ir::Attribute = i;
                                            match i {
                                                ::rustc_attr_ir::Attribute::Parsed(AttributeKind::Stability {
                                                    span, .. }) => {
                                                    break 'done Some(*span);
                                                }
                                                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                                    {}
                                                    #[deny(unreachable_patterns)]
                                                    _ => {}
                                            }
                                        }
                                        None
                                    }
                                }
                            } {
                    let item_sp = self.tcx.def_span(def_id);
                    match stab_since {
                        StableSince::Current => {
                            self.tcx.dcx().emit_err(diagnostics::CannotStabilizeDeprecated {
                                    span,
                                    item_sp,
                                });
                        }
                        StableSince::Version(stab_since) => {
                            if dep_since < stab_since {
                                self.tcx.dcx().emit_err(diagnostics::CannotStabilizeDeprecated {
                                        span,
                                        item_sp,
                                    });
                            }
                        }
                        StableSince::Err(_) => {}
                    }
                }
            }
            let fn_sig = self.tcx.hir_node_by_def_id(def_id).fn_sig();
            if let Some(fn_sig) = fn_sig &&
                            !#[allow(non_exhaustive_omitted_patterns)] match fn_sig.header.constness
                                    {
                                    Constness::Const { .. } => true,
                                    _ => false,
                                } && const_stab.is_some() &&
                    {
                            let attrs =
                                self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
                            {
                                'done:
                                    {
                                    for i in attrs {
                                        #[allow(unused_imports)]
                                        use ::rustc_attr_ir::AttributeKind::*;
                                        let i: &::rustc_attr_ir::Attribute = i;
                                        match i {
                                            ::rustc_attr_ir::Attribute::Parsed(AttributeKind::RustcConstStability {
                                                span, .. }) => {
                                                break 'done Some(*span);
                                            }
                                            ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                                {}
                                                #[deny(unreachable_patterns)]
                                                _ => {}
                                        }
                                    }
                                    None
                                }
                            }
                        }.is_some() {
                self.tcx.dcx().emit_err(diagnostics::MissingConstErr {
                        fn_sig_span: fn_sig.span,
                    });
            }
            if let Some(const_stab) = const_stab && let Some(fn_sig) = fn_sig
                            && const_stab.is_const_stable() &&
                        !stab.is_some_and(|s| s.is_stable()) &&
                    let Some(path_span) =
                        {
                            let attrs =
                                self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
                            {
                                'done:
                                    {
                                    for i in attrs {
                                        #[allow(unused_imports)]
                                        use ::rustc_attr_ir::AttributeKind::*;
                                        let i: &::rustc_attr_ir::Attribute = i;
                                        match i {
                                            ::rustc_attr_ir::Attribute::Parsed(AttributeKind::RustcConstStability {
                                                span, .. }) => {
                                                break 'done Some(*span);
                                            }
                                            ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                                {}
                                                #[deny(unreachable_patterns)]
                                                _ => {}
                                        }
                                    }
                                    None
                                }
                            }
                        } {
                self.tcx.dcx().emit_err(diagnostics::ConstStableNotStable {
                        fn_sig_span: fn_sig.span,
                        path_span,
                    });
            }
            if let Some(stab) = &const_stab && stab.is_const_stable() &&
                        stab.const_stable_indirect &&
                    let Some(span) =
                        {
                            let attrs =
                                self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
                            {
                                'done:
                                    {
                                    for i in attrs {
                                        #[allow(unused_imports)]
                                        use ::rustc_attr_ir::AttributeKind::*;
                                        let i: &::rustc_attr_ir::Attribute = i;
                                        match i {
                                            ::rustc_attr_ir::Attribute::Parsed(AttributeKind::RustcConstStability {
                                                span, .. }) => {
                                                break 'done Some(*span);
                                            }
                                            ::rustc_attr_ir::Attribute::Unparsed(..) =>
                                                {}
                                                #[deny(unreachable_patterns)]
                                                _ => {}
                                        }
                                    }
                                    None
                                }
                            }
                        } {
                self.tcx.dcx().emit_err(diagnostics::RustcConstStableIndirectPairing {
                        span,
                    });
            }
        }
    }
}#[instrument(level = "trace", skip(self))]
321    fn check_compatible_stability(&self, def_id: LocalDefId) {
322        if !self.tcx.features().staged_api() {
323            return;
324        }
325
326        let depr = self.tcx.lookup_deprecation_entry(def_id);
327        let stab = self.tcx.lookup_stability(def_id);
328        let const_stab = self.tcx.lookup_const_stability(def_id);
329
330        macro_rules! find_attr_span {
331            ($name:ident) => {{
332                let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id));
333                find_attr!(attrs, AttributeKind::$name { span, .. } => *span)
334            }}
335        }
336
337        if stab.is_none()
338            && depr.map_or(false, |d| d.attr.is_since_rustc_version())
339            && let Some(span) = find_attr_span!(Deprecated)
340        {
341            self.tcx.dcx().emit_err(diagnostics::DeprecatedAttribute { span });
342        }
343
344        if let Some(stab) = stab {
345            // Error if prohibited, or can't inherit anything from a container.
346            let kind = annotation_kind(self.tcx, def_id);
347            if kind == AnnotationKind::Prohibited
348                || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some())
349            {
350                if let Some(span) = find_attr_span!(Stability) {
351                    let item_sp = self.tcx.def_span(def_id);
352                    self.tcx.dcx().emit_err(diagnostics::UselessStability { span, item_sp });
353                }
354            }
355
356            // Check if deprecated_since < stable_since. If it is,
357            // this is *almost surely* an accident.
358            if let Some(depr) = depr
359                && let DeprecatedSince::RustcVersion(dep_since) = depr.attr.since
360                && let StabilityLevel::Stable { since: stab_since, .. } = stab.level
361                && let Some(span) = find_attr_span!(Stability)
362            {
363                let item_sp = self.tcx.def_span(def_id);
364                match stab_since {
365                    StableSince::Current => {
366                        self.tcx
367                            .dcx()
368                            .emit_err(diagnostics::CannotStabilizeDeprecated { span, item_sp });
369                    }
370                    StableSince::Version(stab_since) => {
371                        if dep_since < stab_since {
372                            self.tcx
373                                .dcx()
374                                .emit_err(diagnostics::CannotStabilizeDeprecated { span, item_sp });
375                        }
376                    }
377                    StableSince::Err(_) => {
378                        // An error already reported. Assume the unparseable stabilization
379                        // version is older than the deprecation version.
380                    }
381                }
382            }
383        }
384
385        // If the current node is a function with const stability attributes (directly given or
386        // implied), check if the function/method is const or the parent impl block is const.
387        let fn_sig = self.tcx.hir_node_by_def_id(def_id).fn_sig();
388        if let Some(fn_sig) = fn_sig
389            && !matches!(fn_sig.header.constness, Constness::Const { .. })
390            && const_stab.is_some()
391            && find_attr_span!(RustcConstStability).is_some()
392        {
393            self.tcx.dcx().emit_err(diagnostics::MissingConstErr { fn_sig_span: fn_sig.span });
394        }
395
396        // If this is marked const *stable*, it must also be regular-stable.
397        if let Some(const_stab) = const_stab
398            && let Some(fn_sig) = fn_sig
399            && const_stab.is_const_stable()
400            && !stab.is_some_and(|s| s.is_stable())
401            && let Some(path_span) = find_attr_span!(RustcConstStability)
402        {
403            self.tcx.dcx().emit_err(diagnostics::ConstStableNotStable {
404                fn_sig_span: fn_sig.span,
405                path_span,
406            });
407        }
408
409        if let Some(stab) = &const_stab
410            && stab.is_const_stable()
411            && stab.const_stable_indirect
412            && let Some(span) = find_attr_span!(RustcConstStability)
413        {
414            self.tcx.dcx().emit_err(diagnostics::RustcConstStableIndirectPairing { span });
415        }
416    }
417
418    {}
#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("check_missing_stability",
                                    "rustc_passes::stability", ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("/rustc-dev/923c95cdf5ba65cea505aa2ea829f578e1506ed8/compiler/rustc_passes/src/stability.rs"),
                                    ::tracing_core::__macro_support::Option::Some(418u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_passes::stability"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("def_id")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("def_id");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&def_id)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let stab = self.tcx.lookup_stability(def_id);
            self.tcx.ensure_ok().lookup_const_stability(def_id);
            if !self.tcx.sess.is_test_crate() && stab.is_none() &&
                    self.effective_visibilities.is_reachable(def_id) {
                let descr = self.tcx.def_descr(def_id.to_def_id());
                let span = self.tcx.def_span(def_id);
                self.tcx.dcx().emit_err(diagnostics::MissingStabilityAttr {
                        span,
                        descr,
                    });
            }
        }
    }
}#[instrument(level = "debug", skip(self))]
419    fn check_missing_stability(&self, def_id: LocalDefId) {
420        let stab = self.tcx.lookup_stability(def_id);
421        self.tcx.ensure_ok().lookup_const_stability(def_id);
422        if !self.tcx.sess.is_test_crate()
423            && stab.is_none()
424            && self.effective_visibilities.is_reachable(def_id)
425        {
426            let descr = self.tcx.def_descr(def_id.to_def_id());
427            let span = self.tcx.def_span(def_id);
428            self.tcx.dcx().emit_err(diagnostics::MissingStabilityAttr { span, descr });
429        }
430    }
431
432    fn check_missing_const_stability(&self, def_id: LocalDefId) {
433        let is_const = self.tcx.is_const_fn(def_id.to_def_id())
434            || (self.tcx.def_kind(def_id.to_def_id()) == DefKind::Trait
435                && self.tcx.is_const_trait(def_id.to_def_id()));
436
437        // Reachable const fn/trait must have a stability attribute.
438        if is_const
439            && self.effective_visibilities.is_reachable(def_id)
440            && self.tcx.lookup_const_stability(def_id).is_none()
441        {
442            let span = self.tcx.def_span(def_id);
443            let descr = self.tcx.def_descr(def_id.to_def_id());
444            self.tcx.dcx().emit_err(diagnostics::MissingConstStabAttr { span, descr });
445        }
446    }
447}
448
449impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
450    type NestedFilter = nested_filter::OnlyBodies;
451
452    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
453        self.tcx
454    }
455
456    fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
457        self.check_compatible_stability(i.owner_id.def_id);
458
459        // Inherent impls and foreign modules serve only as containers for other items,
460        // they don't have their own stability. They still can be annotated as unstable
461        // and propagate this instability to children, but this annotation is completely
462        // optional. They inherit stability from their parents when unannotated.
463        if !#[allow(non_exhaustive_omitted_patterns)] match i.kind {
    hir::ItemKind::Impl(hir::Impl { of_trait: None, .. }) |
        hir::ItemKind::ForeignMod { .. } => true,
    _ => false,
}matches!(
464            i.kind,
465            hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
466                | hir::ItemKind::ForeignMod { .. }
467        ) {
468            self.check_missing_stability(i.owner_id.def_id);
469        }
470
471        // Ensure stable `const fn` have a const stability attribute.
472        self.check_missing_const_stability(i.owner_id.def_id);
473
474        intravisit::walk_item(self, i)
475    }
476
477    fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
478        self.check_compatible_stability(ti.owner_id.def_id);
479        self.check_missing_stability(ti.owner_id.def_id);
480        intravisit::walk_trait_item(self, ti);
481    }
482
483    fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
484        self.check_compatible_stability(ii.owner_id.def_id);
485        if let hir::ImplItemImplKind::Inherent { .. } = ii.impl_kind {
486            self.check_missing_stability(ii.owner_id.def_id);
487            self.check_missing_const_stability(ii.owner_id.def_id);
488        }
489        intravisit::walk_impl_item(self, ii);
490    }
491
492    fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
493        self.check_compatible_stability(var.def_id);
494        self.check_missing_stability(var.def_id);
495        if let Some(ctor_def_id) = var.data.ctor_def_id() {
496            self.check_missing_stability(ctor_def_id);
497        }
498        intravisit::walk_variant(self, var);
499    }
500
501    fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
502        self.check_compatible_stability(s.def_id);
503        self.check_missing_stability(s.def_id);
504        intravisit::walk_field_def(self, s);
505    }
506
507    fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
508        self.check_compatible_stability(i.owner_id.def_id);
509        self.check_missing_stability(i.owner_id.def_id);
510        intravisit::walk_foreign_item(self, i);
511    }
512
513    fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
514        self.check_compatible_stability(p.def_id);
515        // Note that we don't need to `check_missing_stability` for default generic parameters,
516        // as we assume that any default generic parameters without attributes are automatically
517        // stable (assuming they have not inherited instability from their parent).
518        intravisit::walk_generic_param(self, p);
519    }
520}
521
522/// Cross-references the feature names of unstable APIs with enabled
523/// features and possibly prints errors.
524fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, mod_id: LocalModId) {
525    let mut checker = Checker { tcx, mod_id, unstable_reexports: FxIndexMap::default() };
526    tcx.hir_visit_item_likes_in_module(mod_id, &mut checker);
527    checker.emit_ineffective_unstable_reexports();
528
529    let is_staged_api =
530        tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api();
531    if is_staged_api {
532        let effective_visibilities = &tcx.effective_visibilities(());
533        let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
534        if mod_id.is_top_level_module() {
535            missing.check_missing_stability(CRATE_DEF_ID);
536        }
537        tcx.hir_visit_item_likes_in_module(mod_id, &mut missing);
538    }
539
540    if mod_id.is_top_level_module() {
541        check_unused_or_stable_features(tcx)
542    }
543}
544
545pub(crate) fn provide(providers: &mut Providers) {
546    *providers = Providers {
547        check_mod_unstable_api_usage,
548        stability_implications,
549        lookup_stability,
550        lookup_const_stability,
551        lookup_default_body_stability,
552        lookup_deprecation_entry,
553        ..*providers
554    };
555}
556
557struct UnstableReexport {
558    hir_id: HirId,
559    span: Span,
560    has_target: bool,
561    all_targets_stable: bool,
562}
563
564struct Checker<'tcx> {
565    tcx: TyCtxt<'tcx>,
566    mod_id: LocalModId,
567    unstable_reexports: FxIndexMap<Span, UnstableReexport>,
568}
569
570impl<'tcx> Checker<'tcx> {
571    fn unstable_reexport_span(&self, item: &'tcx hir::Item<'tcx>) -> Option<Span> {
572        let attrs = self.tcx.hir_attrs(item.hir_id());
573        let (stability, span) =
574            {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(Stability { stability, span
                    }) => {
                    break 'done Some((*stability, *span));
                }
                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, Stability { stability, span } => (*stability, *span))?;
575
576        stability.level.is_unstable().then_some(span)
577    }
578
579    fn classify_reexport_targets<Id>(
580        &self,
581        targets: impl IntoIterator<Item = Res<Id>>,
582    ) -> (bool, bool) {
583        let mut has_target = false;
584        let mut all_targets_stable = true;
585
586        for res in targets {
587            match res {
588                Res::Def(_, def_id) => {
589                    has_target = true;
590
591                    match self.tcx.lookup_stability(def_id) {
592                        Some(stability) if stability.level.is_unstable() => {
593                            all_targets_stable = false;
594                        }
595                        Some(_) => {}
596
597                        None => {
598                            // Items from crates without staged API metadata are
599                            // effectively stable. Unmarked items in staged API
600                            // crates are diagnosed by the existing stability checks.
601                            if self.tcx.lookup_stability(def_id.krate.as_def_id()).is_some() {
602                                all_targets_stable = false;
603                            }
604                        }
605                    }
606                }
607
608                // Primitives are stable and have no DefId.
609                Res::PrimTy(_) => {
610                    has_target = true;
611                }
612
613                // Do not lint if the target cannot be classified.
614                _ => {
615                    all_targets_stable = false;
616                }
617            }
618        }
619
620        (has_target, all_targets_stable)
621    }
622
623    fn record_unstable_reexport(
624        &mut self,
625        item: &'tcx hir::Item<'tcx>,
626        attr_span: Span,
627        span: Span,
628        has_target: bool,
629        all_targets_stable: bool,
630    ) {
631        let entry = self.unstable_reexports.entry(attr_span).or_insert(UnstableReexport {
632            hir_id: item.hir_id(),
633            span,
634            has_target: false,
635            all_targets_stable: true,
636        });
637
638        entry.has_target |= has_target;
639        entry.all_targets_stable &= all_targets_stable;
640    }
641
642    fn check_single_unstable_reexport(
643        &mut self,
644        item: &'tcx hir::Item<'tcx>,
645        path: &'tcx UsePath<'tcx>,
646    ) {
647        let Some(attr_span) = self.unstable_reexport_span(item) else {
648            return;
649        };
650
651        let (has_target, all_targets_stable) =
652            self.classify_reexport_targets(path.res.present_items());
653
654        self.record_unstable_reexport(item, attr_span, path.span, has_target, all_targets_stable);
655    }
656
657    fn check_glob_unstable_reexport(
658        &mut self,
659        item: &'tcx hir::Item<'tcx>,
660        path: &'tcx UsePath<'tcx>,
661    ) {
662        let Some(attr_span) = self.unstable_reexport_span(item) else {
663            return;
664        };
665
666        let glob_def_id = item.owner_id.def_id.to_def_id();
667
668        let targets = self
669            .tcx
670            .module_children_local(self.mod_id.to_local_def_id())
671            .iter()
672            .filter(|child| {
673                child.reexport_chain.iter().any(|reexport| reexport.id() == Some(glob_def_id))
674            })
675            .map(|child| child.res);
676
677        let (has_target, all_targets_stable) = self.classify_reexport_targets(targets);
678
679        self.record_unstable_reexport(item, attr_span, path.span, has_target, all_targets_stable);
680    }
681
682    fn containing_module_is_unstable(&self) -> bool {
683        self.tcx
684            .lookup_stability(self.mod_id.to_local_def_id())
685            .is_some_and(|stability| stability.level.is_unstable())
686    }
687
688    fn emit_ineffective_unstable_reexports(&self) {
689        // an unstable module already makes its re-exports unstable
690        // keep the explicit annotation without linting it as ineffective
691        if self.unstable_reexports.is_empty() || self.containing_module_is_unstable() {
692            return;
693        }
694
695        for reexport in self.unstable_reexports.values() {
696            if reexport.has_target && reexport.all_targets_stable {
697                self.tcx.emit_node_span_lint(
698                    INEFFECTIVE_UNSTABLE_REEXPORTS,
699                    reexport.hir_id,
700                    reexport.span,
701                    diagnostics::IneffectiveUnstableReexport,
702                );
703            }
704        }
705    }
706}
707
708impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
709    type NestedFilter = nested_filter::OnlyBodies;
710
711    /// Because stability levels are scoped lexically, we want to walk
712    /// nested items in the context of the outer item, so enable
713    /// deep-walking.
714    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
715        self.tcx
716    }
717
718    fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
719        match item.kind {
720            hir::ItemKind::ExternCrate(_, ident) => {
721                // compiler-generated `extern crate` items have a dummy span.
722                // `std` is still checked for the `restricted-std` feature.
723                if item.span.is_dummy() && ident.name != sym::std {
724                    return;
725                }
726
727                let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else {
728                    return;
729                };
730                let def_id = cnum.as_def_id();
731                self.tcx.check_stability(def_id, Some(item.hir_id()), item.span, None);
732            }
733
734            hir::ItemKind::Use(path, hir::UseKind::Single(_))
735                if self.tcx.features().staged_api()
736                    && self.tcx.local_visibility(item.owner_id.def_id).is_public() =>
737            {
738                self.check_single_unstable_reexport(item, path);
739            }
740
741            hir::ItemKind::Use(path, hir::UseKind::Glob)
742                if self.tcx.features().staged_api()
743                    && self.tcx.local_visibility(item.owner_id.def_id).is_public() =>
744            {
745                self.check_glob_unstable_reexport(item, path);
746            }
747
748            // For implementations of traits, check the stability of each item
749            // individually as it's possible to have a stable trait with unstable
750            // items.
751            hir::ItemKind::Impl(hir::Impl {
752                of_trait: Some(of_trait),
753                self_ty,
754                items,
755                constness,
756                ..
757            }) => {
758                let features = self.tcx.features();
759                if features.staged_api() {
760                    let attrs = self.tcx.hir_attrs(item.hir_id());
761                    let stab = {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(Stability { stability, span
                    }) => {
                    break 'done Some((*stability, *span));
                }
                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, Stability{stability, span} => (*stability, *span));
762
763                    // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
764                    let const_stab =
765                        {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(RustcConstStability {
                    stability, .. }) => {
                    break 'done Some(*stability);
                }
                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, RustcConstStability{stability, ..} => *stability);
766
767                    let unstable_feature_stab = {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(UnstableFeatureBound(i)) =>
                    {
                    break 'done Some(i);
                }
                ::rustc_attr_ir::Attribute::Unparsed(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, UnstableFeatureBound(i) => i)
768                        .map(|i| i.as_slice())
769                        .unwrap_or_default();
770
771                    // If this impl block has an #[unstable] attribute, give an
772                    // error if all involved types and traits are stable, because
773                    // it will have no effect.
774                    // See: https://github.com/rust-lang/rust/issues/55436
775                    //
776                    // The exception is when there are both  #[unstable_feature_bound(..)] and
777                    //  #![unstable(feature = "..", issue = "..")] that have the same symbol because
778                    // that can effectively mark an impl as unstable.
779                    //
780                    // For example:
781                    // ```
782                    // #[unstable_feature_bound(feat_foo)]
783                    // #[unstable(feature = "feat_foo", issue = "none")]
784                    // impl Foo for Bar {}
785                    // ```
786                    if let Some((
787                        Stability { level: StabilityLevel::Unstable { .. }, feature },
788                        span,
789                    )) = stab
790                    {
791                        let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
792                        c.visit_ty_unambig(self_ty);
793                        c.visit_trait_ref(&of_trait.trait_ref);
794
795                        // Skip the lint if the impl is marked as unstable using
796                        // #[unstable_feature_bound(..)]
797                        let mut unstable_feature_bound_in_effect = false;
798                        for (unstable_bound_feat_name, _) in unstable_feature_stab {
799                            if *unstable_bound_feat_name == feature {
800                                unstable_feature_bound_in_effect = true;
801                            }
802                        }
803
804                        // do not lint when the trait isn't resolved, since resolution error should
805                        // be fixed first
806                        if of_trait.trait_ref.path.res != Res::Err
807                            && c.fully_stable
808                            && !unstable_feature_bound_in_effect
809                        {
810                            self.tcx.emit_node_span_lint(
811                                INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
812                                item.hir_id(),
813                                span,
814                                diagnostics::IneffectiveUnstableImpl,
815                            );
816                        }
817                    }
818
819                    if features.const_trait_impl()
820                        && let hir::Constness::Const { .. } = constness
821                    {
822                        let stable_or_implied_stable = match const_stab {
823                            None => true,
824                            Some(stab) if stab.is_const_stable() => {
825                                // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable
826                                // needs to have an error emitted.
827                                // Note: Remove this error once `const_trait_impl` is stabilized
828                                self.tcx.dcx().emit_err(diagnostics::TraitImplConstStable {
829                                    span: item.span,
830                                });
831                                true
832                            }
833                            Some(_) => false,
834                        };
835
836                        if let Some(trait_id) = of_trait.trait_ref.trait_def_id()
837                            && let Some(const_stab) = self.tcx.lookup_const_stability(trait_id)
838                        {
839                            // the const stability of a trait impl must match the const stability on the trait.
840                            if const_stab.is_const_stable() != stable_or_implied_stable {
841                                let trait_span = self.tcx.def_ident_span(trait_id).unwrap();
842
843                                let impl_stability = if stable_or_implied_stable {
844                                    diagnostics::ImplConstStability::Stable { span: item.span }
845                                } else {
846                                    diagnostics::ImplConstStability::Unstable { span: item.span }
847                                };
848                                let trait_stability = if const_stab.is_const_stable() {
849                                    diagnostics::TraitConstStability::Stable { span: trait_span }
850                                } else {
851                                    diagnostics::TraitConstStability::Unstable { span: trait_span }
852                                };
853
854                                self.tcx.dcx().emit_err(
855                                    diagnostics::TraitImplConstStabilityMismatch {
856                                        span: item.span,
857                                        impl_stability,
858                                        trait_stability,
859                                    },
860                                );
861                            }
862                        }
863                    }
864                }
865
866                if let hir::Constness::Const { .. } = constness
867                    && let Some(def_id) = of_trait.trait_ref.trait_def_id()
868                {
869                    // FIXME(const_trait_impl): Improve the span here.
870                    self.tcx.check_const_stability(
871                        def_id,
872                        of_trait.trait_ref.path.span,
873                        of_trait.trait_ref.path.span,
874                    );
875                }
876
877                for impl_item_ref in items {
878                    let impl_item = self.tcx.associated_item(impl_item_ref.owner_id);
879
880                    if let AssocContainer::TraitImpl(Ok(def_id)) = impl_item.container {
881                        // Pass `None` to skip deprecation warnings.
882                        self.tcx.check_stability(
883                            def_id,
884                            None,
885                            self.tcx.def_span(impl_item_ref.owner_id),
886                            None,
887                        );
888                    }
889                }
890            }
891
892            _ => (/* pass */),
893        }
894        intravisit::walk_item(self, item);
895    }
896
897    fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) {
898        match t.modifiers.constness {
899            hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) => {
900                if let Some(def_id) = t.trait_ref.trait_def_id() {
901                    self.tcx.check_const_stability(def_id, t.trait_ref.path.span, span);
902                }
903            }
904            hir::BoundConstness::Never => {}
905        }
906        intravisit::walk_poly_trait_ref(self, t);
907    }
908
909    fn visit_use(&mut self, path: &'tcx UsePath<'tcx>, hir_id: HirId) {
910        let res = path.res;
911
912        // A use item can import something from two namespaces at the same time.
913        // For deprecation/stability we don't want to warn twice.
914        // This specifically happens with constructors for unit/tuple structs.
915        if let Some(ty_ns_res) = res.type_ns
916            && let Some(value_ns_res) = res.value_ns
917            && let Some(type_ns_did) = ty_ns_res.opt_def_id()
918            && let Some(value_ns_did) = value_ns_res.opt_def_id()
919            && let DefKind::Ctor(.., _) = self.tcx.def_kind(value_ns_did)
920            && self.tcx.parent(value_ns_did) == type_ns_did
921        {
922            // Only visit the value namespace path when we've detected a duplicate,
923            // not the type namespace path.
924            let UsePath { segments, res: _, span } = *path;
925            self.visit_path(&Path { segments, res: value_ns_res, span }, hir_id);
926
927            // Though, visit the macro namespace if it exists,
928            // regardless of the checks above relating to constructors.
929            if let Some(res) = res.macro_ns {
930                self.visit_path(&Path { segments, res, span }, hir_id);
931            }
932        } else {
933            // if there's no duplicate, just walk as normal
934            intravisit::walk_use(self, path, hir_id)
935        }
936    }
937
938    fn visit_path(&mut self, path: &hir::Path<'tcx>, id: hir::HirId) {
939        if let Some(def_id) = path.res.opt_def_id() {
940            let method_span = path.segments.last().map(|s| s.ident.span);
941            let item_is_allowed = self.tcx.check_stability_allow_unstable(
942                def_id,
943                Some(id),
944                path.span,
945                method_span,
946                if is_unstable_reexport(self.tcx, id) {
947                    AllowUnstable::Yes
948                } else {
949                    AllowUnstable::No
950                },
951            );
952
953            if item_is_allowed {
954                // The item itself is allowed; check whether the path there is also allowed.
955                let is_allowed_through_unstable_modules: Option<(Symbol, Symbol)> =
956                    self.tcx.lookup_stability(def_id).and_then(|stab| match stab.level {
957                        StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
958                            allowed_through_unstable_modules
959                        }
960                        _ => None,
961                    });
962
963                // Check parent modules stability as well if the item the path refers to is itself
964                // stable. We only emit errors for unstable path segments if the item is stable
965                // or allowed because stability is often inherited, so the most common case is that
966                // both the segments and the item are unstable behind the same feature flag.
967                //
968                // We check here rather than in `visit_path_segment` to prevent visiting the last
969                // path segment twice
970                //
971                // We include special cases via #[rustc_allowed_through_unstable_modules] for items
972                // that were accidentally stabilized through unstable paths before this check was
973                // added, such as `core::intrinsics::transmute`
974                let parents = path.segments.iter().rev().skip(1);
975                for path_segment in parents {
976                    if let Some(def_id) = path_segment.res.opt_def_id() {
977                        match is_allowed_through_unstable_modules {
978                            None => {
979                                // Emit a hard stability error if this path is not stable.
980
981                                // use `None` for id to prevent deprecation check
982                                self.tcx.check_stability_allow_unstable(
983                                    def_id,
984                                    None,
985                                    path_segment.ident.span,
986                                    None,
987                                    if is_unstable_reexport(self.tcx, id) {
988                                        AllowUnstable::Yes
989                                    } else {
990                                        AllowUnstable::No
991                                    },
992                                );
993                            }
994                            Some((message, suggestion)) => {
995                                // Call the stability check directly so that we can control which
996                                // diagnostic is emitted.
997                                let eval_result = self.tcx.eval_stability_allow_unstable(
998                                    def_id,
999                                    None,
1000                                    path.span,
1001                                    None,
1002                                    if is_unstable_reexport(self.tcx, id) {
1003                                        AllowUnstable::Yes
1004                                    } else {
1005                                        AllowUnstable::No
1006                                    },
1007                                );
1008                                let is_allowed = #[allow(non_exhaustive_omitted_patterns)] match eval_result {
    EvalResult::Allow => true,
    _ => false,
}matches!(eval_result, EvalResult::Allow);
1009                                if !is_allowed {
1010                                    // Show a deprecation message.
1011                                    let [.., intrinsics_module, _intrinsic] = path.segments else {
1012                                        bug_impl(Some(path.span),
    format_args!("no module for `is_allowed_through_unstable_modules` intrinsic {0:?}",
        path), Location::caller())span_bug!(
1013                                            path.span,
1014                                            "no module for `is_allowed_through_unstable_modules` intrinsic {path:?}"
1015                                        )
1016                                    };
1017                                    let diag = diagnostics::RustcAtumSuggestion {
1018                                        message,
1019                                        import_span: path.span,
1020                                        unstable_mod_span: { intrinsics_module.ident.span },
1021                                        module: intrinsics_module.ident,
1022                                        suggestion,
1023                                    };
1024                                    self.tcx.emit_node_span_lint(
1025                                        DEPRECATED,
1026                                        id,
1027                                        method_span.unwrap_or(path.span),
1028                                        diag,
1029                                    );
1030                                }
1031                            }
1032                        }
1033                    }
1034                }
1035            }
1036        }
1037
1038        intravisit::walk_path(self, path)
1039    }
1040}
1041
1042/// Check whether a path is a `use` item that has been marked as unstable.
1043///
1044/// See issue #94972 for details on why this is a special case
1045fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
1046    // Get the LocalDefId so we can lookup the item to check the kind.
1047    let Some(owner) = id.as_owner() else {
1048        return false;
1049    };
1050    let def_id = owner.def_id;
1051
1052    let Some(stab) = tcx.lookup_stability(def_id) else {
1053        return false;
1054    };
1055
1056    if stab.level.is_stable() {
1057        // The re-export is not marked as unstable, don't override
1058        return false;
1059    }
1060
1061    // If this is a path that isn't a use, we don't need to do anything special
1062    if !#[allow(non_exhaustive_omitted_patterns)] match tcx.hir_expect_item(def_id).kind
    {
    ItemKind::Use(..) => true,
    _ => false,
}matches!(tcx.hir_expect_item(def_id).kind, ItemKind::Use(..)) {
1063        return false;
1064    }
1065
1066    true
1067}
1068
1069struct CheckTraitImplStable<'tcx> {
1070    tcx: TyCtxt<'tcx>,
1071    fully_stable: bool,
1072}
1073
1074impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
1075    fn visit_path(&mut self, path: &hir::Path<'tcx>, _id: hir::HirId) {
1076        if let Some(def_id) = path.res.opt_def_id()
1077            && let Some(stab) = self.tcx.lookup_stability(def_id)
1078        {
1079            self.fully_stable &= stab.level.is_stable();
1080        }
1081        intravisit::walk_path(self, path)
1082    }
1083
1084    fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) {
1085        if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
1086            if let Some(stab) = self.tcx.lookup_stability(trait_did) {
1087                self.fully_stable &= stab.level.is_stable();
1088            }
1089        }
1090        intravisit::walk_trait_ref(self, t)
1091    }
1092
1093    fn visit_ty(&mut self, t: &'tcx Ty<'tcx, AmbigArg>) {
1094        if let TyKind::FnPtr(function) = t.kind {
1095            if extern_abi_stability(function.abi).is_err() {
1096                self.fully_stable = false;
1097            }
1098        }
1099        intravisit::walk_ty(self, t)
1100    }
1101}
1102
1103/// Given the list of enabled features that were not language features (i.e., that
1104/// were expected to be library features), and the list of features used from
1105/// libraries, identify activated features that don't exist and error about them.
1106// This is `pub` for rustdoc. rustc should call it through `check_mod_unstable_api_usage`.
1107pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
1108    let _prof_timer = tcx.sess.timer("unused_lib_feature_checking");
1109
1110    let enabled_lang_features = tcx.features().enabled_lang_features();
1111    let mut lang_features = UnordSet::default();
1112    for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features {
1113        if let Some(version) = stable_since {
1114            // Mark the feature as enabled, to ensure that it is not marked as unused.
1115            let _ = tcx.features().enabled(*gate_name);
1116
1117            // Warn if the user has enabled an already-stable lang feature.
1118            unnecessary_stable_feature_lint(tcx, *attr_sp, *gate_name, *version);
1119        }
1120        if !lang_features.insert(gate_name) {
1121            // Warn if the user enables a lang feature multiple times.
1122            duplicate_feature_lint(tcx, *attr_sp, *gate_name);
1123        }
1124    }
1125
1126    let enabled_lib_features = tcx.features().enabled_lib_features();
1127    let mut remaining_lib_features = FxIndexMap::default();
1128    for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features {
1129        if remaining_lib_features.contains_key(gate_name) {
1130            // Warn if the user enables a lib feature multiple times.
1131            duplicate_feature_lint(tcx, *attr_sp, *gate_name);
1132        }
1133        remaining_lib_features.insert(*gate_name, *attr_sp);
1134    }
1135    // `stdbuild` has special handling for `libc`, so we need to
1136    // recognise the feature when building std.
1137    // Likewise, libtest is handled specially, so `test` isn't
1138    // available as we'd like it to be.
1139    // FIXME: only remove `libc` when `stdbuild` is enabled.
1140    // FIXME: remove special casing for `test`.
1141    // FIXME(#120456) - is `swap_remove` correct?
1142    remaining_lib_features.swap_remove(&sym::libc);
1143    remaining_lib_features.swap_remove(&sym::test);
1144
1145    /// For each feature in `defined_features`..
1146    ///
1147    /// - If it is in `remaining_lib_features` (those features with `#![feature(..)]` attributes in
1148    ///   the current crate), check if it is stable (or partially stable) and thus an unnecessary
1149    ///   attribute.
1150    /// - If it is in `remaining_implications` (a feature that is referenced by an `implied_by`
1151    ///   from the current crate), then remove it from the remaining implications.
1152    ///
1153    /// Once this function has been invoked for every feature (local crate and all extern crates),
1154    /// then..
1155    ///
1156    /// - If features remain in `remaining_lib_features`, then the user has enabled a feature that
1157    ///   does not exist.
1158    /// - If features remain in `remaining_implications`, the `implied_by` refers to a feature that
1159    ///   does not exist.
1160    ///
1161    /// By structuring the code in this way: checking the features defined from each crate one at a
1162    /// time, less loading from metadata is performed and thus compiler performance is improved.
1163    fn check_features<'tcx>(
1164        tcx: TyCtxt<'tcx>,
1165        remaining_lib_features: &mut FxIndexMap<Symbol, Span>,
1166        remaining_implications: &mut UnordMap<Symbol, Symbol>,
1167        defined_features: &LibFeatures,
1168        all_implications: &UnordMap<Symbol, Symbol>,
1169    ) {
1170        for (feature, stability) in defined_features.to_sorted_vec() {
1171            if let FeatureStability::AcceptedSince(since) = stability
1172                && let Some(span) = remaining_lib_features.get(&feature)
1173            {
1174                // Mark the feature as enabled, to ensure that it is not marked as unused.
1175                let _ = tcx.features().enabled(feature);
1176
1177                // Warn if the user has enabled an already-stable lib feature.
1178                if let Some(implies) = all_implications.get(&feature) {
1179                    unnecessary_partially_stable_feature_lint(tcx, *span, feature, *implies, since);
1180                } else {
1181                    unnecessary_stable_feature_lint(tcx, *span, feature, since);
1182                }
1183            }
1184            // FIXME(#120456) - is `swap_remove` correct?
1185            remaining_lib_features.swap_remove(&feature);
1186
1187            // `feature` is the feature doing the implying, but `implied_by` is the feature with
1188            // the attribute that establishes this relationship. `implied_by` is guaranteed to be a
1189            // feature defined in the local crate because `remaining_implications` is only the
1190            // implications from this crate.
1191            remaining_implications.remove(&feature);
1192
1193            if let FeatureStability::Unstable { old_name: Some(alias) } = stability
1194                && let Some(span) = remaining_lib_features.swap_remove(&alias)
1195            {
1196                tcx.dcx().emit_err(diagnostics::RenamedFeature { span, feature, alias });
1197            }
1198
1199            if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
1200                break;
1201            }
1202        }
1203    }
1204
1205    // All local crate implications need to have the feature that implies it confirmed to exist.
1206    let mut remaining_implications = tcx.stability_implications(LOCAL_CRATE).clone();
1207
1208    // We always collect the lib features enabled in the current crate, even if there are
1209    // no unknown features, because the collection also does feature attribute validation.
1210    let local_defined_features = tcx.lib_features(LOCAL_CRATE);
1211    if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() {
1212        let crates = tcx.crates(());
1213
1214        // Loading the implications of all crates is unavoidable to be able to emit the partial
1215        // stabilization diagnostic, but it can be avoided when there are no
1216        // `remaining_lib_features`.
1217        let mut all_implications = remaining_implications.clone();
1218        for &cnum in crates {
1219            all_implications
1220                .extend_unord(tcx.stability_implications(cnum).items().map(|(k, v)| (*k, *v)));
1221        }
1222
1223        check_features(
1224            tcx,
1225            &mut remaining_lib_features,
1226            &mut remaining_implications,
1227            local_defined_features,
1228            &all_implications,
1229        );
1230
1231        for &cnum in crates {
1232            if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
1233                break;
1234            }
1235            check_features(
1236                tcx,
1237                &mut remaining_lib_features,
1238                &mut remaining_implications,
1239                tcx.lib_features(cnum),
1240                &all_implications,
1241            );
1242        }
1243
1244        if !remaining_lib_features.is_empty() {
1245            let lang_features =
1246                UNSTABLE_LANG_FEATURES.iter().map(|feature| feature.name).collect::<Vec<_>>();
1247            let lib_features = crates
1248                .iter()
1249                .flat_map(|&cnum| {
1250                    tcx.lib_features(cnum).stability.keys().copied().into_sorted_stable_ord()
1251                })
1252                .collect::<Vec<_>>();
1253
1254            let valid_feature_names = [lang_features, lib_features].concat();
1255
1256            // Collect all of the marked as "removed" features
1257            let unstable_removed_features = crates
1258                .iter()
1259                .flat_map(|&cnum| {
1260                    {
    {
        'done:
            {
            for i in
                ::rustc_attr_ir::HasAttrs::get_attrs(cnum.as_def_id(), &tcx) {
                #[allow(unused_imports)]
                use ::rustc_attr_ir::AttributeKind::*;
                let i: &::rustc_attr_ir::Attribute = i;
                match i {
                    ::rustc_attr_ir::Attribute::Parsed(UnstableRemoved(rem_features))
                        => {
                        break 'done Some(rem_features);
                    }
                    ::rustc_attr_ir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, cnum.as_def_id(), UnstableRemoved(rem_features) => rem_features)
1261                        .into_flat_iter()
1262                })
1263                .collect::<Vec<_>>();
1264
1265            for (feature, span) in remaining_lib_features {
1266                if let Some(removed) =
1267                    unstable_removed_features.iter().find(|removed| removed.feature == feature)
1268                {
1269                    tcx.dcx().emit_err(diagnostics::FeatureRemoved {
1270                        span,
1271                        feature,
1272                        reason: removed.reason,
1273                        link: removed.link,
1274                        since: removed.since.to_string(),
1275                    });
1276                } else {
1277                    let suggestion =
1278                        feature.find_similar(&valid_feature_names).map(|(actual_name, _)| {
1279                            diagnostics::MisspelledFeature { span, actual_name }
1280                        });
1281                    tcx.dcx().emit_err(diagnostics::UnknownFeature { span, feature, suggestion });
1282                }
1283            }
1284        }
1285    }
1286
1287    for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() {
1288        let local_defined_features = tcx.lib_features(LOCAL_CRATE);
1289        let span = local_defined_features
1290            .stability
1291            .get(&feature)
1292            .expect("feature that implied another does not exist")
1293            .1;
1294        tcx.dcx().emit_err(diagnostics::ImpliedFeatureNotExist { span, feature, implied_by });
1295    }
1296}
1297
1298fn unnecessary_partially_stable_feature_lint(
1299    tcx: TyCtxt<'_>,
1300    span: Span,
1301    feature: Symbol,
1302    implies: Symbol,
1303    since: Symbol,
1304) {
1305    tcx.emit_node_span_lint(
1306        STABLE_FEATURES,
1307        hir::CRATE_HIR_ID,
1308        span,
1309        diagnostics::UnnecessaryPartialStableFeature {
1310            span,
1311            line: tcx.sess.source_map().span_extend_to_line(span),
1312            feature,
1313            since,
1314            implies,
1315        },
1316    );
1317}
1318
1319fn unnecessary_stable_feature_lint(
1320    tcx: TyCtxt<'_>,
1321    span: Span,
1322    feature: Symbol,
1323    mut since: Symbol,
1324) {
1325    if since.as_str() == VERSION_PLACEHOLDER {
1326        since = sym::env_CFG_RELEASE;
1327    }
1328    tcx.emit_node_span_lint(
1329        STABLE_FEATURES,
1330        hir::CRATE_HIR_ID,
1331        span,
1332        diagnostics::UnnecessaryStableFeature { feature, since },
1333    );
1334}
1335
1336fn duplicate_feature_lint(tcx: TyCtxt<'_>, span: Span, feature: Symbol) {
1337    tcx.emit_node_span_lint(
1338        DUPLICATE_FEATURES,
1339        hir::CRATE_HIR_ID,
1340        span,
1341        diagnostics::DuplicateFeature { feature },
1342    );
1343}