Skip to main content

rustc_middle/middle/
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::NodeId;
7use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, LintBuffer, msg};
8use rustc_feature::GateIssue;
9use rustc_hir::attrs::{DeprecatedSince, Deprecation};
10use rustc_hir::def_id::{DefId, LocalDefId};
11use rustc_hir::{self as hir, ConstStability, DefaultBodyStability, HirId, Stability};
12use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic};
13use rustc_session::Session;
14use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE};
15use rustc_session::lint::{DeprecatedSinceKind, Level, Lint};
16use rustc_session::parse::feature_err_issue;
17use rustc_span::{Span, Symbol, sym};
18use tracing::debug;
19
20pub use self::StabilityLevel::*;
21use crate::ty::TyCtxt;
22use crate::ty::print::with_no_trimmed_paths;
23
24#[derive(#[automatically_derived]
impl ::core::cmp::PartialEq for StabilityLevel {
    #[inline]
    fn eq(&self, other: &StabilityLevel) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::clone::Clone for StabilityLevel {
    #[inline]
    fn clone(&self) -> StabilityLevel { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for StabilityLevel { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for StabilityLevel {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                StabilityLevel::Unstable => "Unstable",
                StabilityLevel::Stable => "Stable",
            })
    }
}Debug)]
25pub enum StabilityLevel {
26    Unstable,
27    Stable,
28}
29
30#[derive(#[automatically_derived]
impl ::core::marker::Copy for UnstableKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for UnstableKind {
    #[inline]
    fn clone(&self) -> UnstableKind {
        let _: ::core::clone::AssertParamIsClone<Span>;
        *self
    }
}Clone)]
31pub enum UnstableKind {
32    /// Enforcing regular stability of an item
33    Regular,
34    /// Enforcing const stability of an item
35    Const(Span),
36}
37
38/// An entry in the `depr_map`.
39#[derive(#[automatically_derived]
impl ::core::marker::Copy for DeprecationEntry { }Copy, #[automatically_derived]
impl ::core::clone::Clone for DeprecationEntry {
    #[inline]
    fn clone(&self) -> DeprecationEntry {
        let _: ::core::clone::AssertParamIsClone<Deprecation>;
        let _: ::core::clone::AssertParamIsClone<Option<LocalDefId>>;
        *self
    }
}Clone, const _: () =
    {
        impl<'__ctx>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_middle::ich::StableHashingContext<'__ctx>>
            for DeprecationEntry {
            #[inline]
            fn hash_stable(&self,
                __hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                match *self {
                    DeprecationEntry {
                        attr: ref __binding_0, origin: ref __binding_1 } => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable, #[automatically_derived]
impl ::core::fmt::Debug for DeprecationEntry {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "DeprecationEntry", "attr", &self.attr, "origin", &&self.origin)
    }
}Debug, const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for DeprecationEntry {
            fn encode(&self, __encoder: &mut __E) {
                match *self {
                    DeprecationEntry {
                        attr: ref __binding_0, origin: ref __binding_1 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for DeprecationEntry {
            fn decode(__decoder: &mut __D) -> Self {
                DeprecationEntry {
                    attr: ::rustc_serialize::Decodable::decode(__decoder),
                    origin: ::rustc_serialize::Decodable::decode(__decoder),
                }
            }
        }
    };Decodable)]
40pub struct DeprecationEntry {
41    /// The metadata of the attribute associated with this entry.
42    pub attr: Deprecation,
43    /// The `DefId` where the attr was originally attached. `None` for non-local
44    /// `DefId`'s.
45    origin: Option<LocalDefId>,
46}
47
48impl DeprecationEntry {
49    pub fn local(attr: Deprecation, def_id: LocalDefId) -> DeprecationEntry {
50        DeprecationEntry { attr, origin: Some(def_id) }
51    }
52
53    pub fn external(attr: Deprecation) -> DeprecationEntry {
54        DeprecationEntry { attr, origin: None }
55    }
56
57    pub fn same_origin(&self, other: &DeprecationEntry) -> bool {
58        match (self.origin, other.origin) {
59            (Some(o1), Some(o2)) => o1 == o2,
60            _ => false,
61        }
62    }
63}
64
65pub fn report_unstable(
66    sess: &Session,
67    feature: Symbol,
68    reason: Option<Symbol>,
69    issue: Option<NonZero<u32>>,
70    suggestion: Option<(Span, String, String, Applicability)>,
71    span: Span,
72    kind: UnstableKind,
73) {
74    let qual = match kind {
75        UnstableKind::Regular => "",
76        UnstableKind::Const(_) => " const",
77    };
78
79    let msg = match reason {
80        Some(r) => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("use of unstable{0} library feature `{1}`: {2}",
                qual, feature, r))
    })format!("use of unstable{qual} library feature `{feature}`: {r}"),
81        None => ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("use of unstable{0} library feature `{1}`",
                qual, feature))
    })format!("use of unstable{qual} library feature `{feature}`"),
82    };
83
84    let mut err = feature_err_issue(sess, feature, span, GateIssue::Library(issue), msg);
85    if let Some((inner_types, msg, sugg, applicability)) = suggestion {
86        err.span_suggestion(inner_types, msg, sugg, applicability);
87    }
88    if let UnstableKind::Const(kw) = kind {
89        err.span_label(kw, "trait is not stable as const yet");
90    }
91    err.emit();
92}
93
94fn deprecation_lint(is_in_effect: bool) -> &'static Lint {
95    if is_in_effect { DEPRECATED } else { DEPRECATED_IN_FUTURE }
96}
97
98#[derive(const _: () =
    {
        impl rustc_errors::Subdiagnostic for DeprecationSuggestion {
            fn add_to_diag<__G>(self, diag: &mut rustc_errors::Diag<'_, __G>)
                where __G: rustc_errors::EmissionGuarantee {
                match self {
                    DeprecationSuggestion {
                        span: __binding_0,
                        kind: __binding_1,
                        suggestion: __binding_2 } => {
                        let __code_0 =
                            [::alloc::__export::must_use({
                                                ::alloc::fmt::format(format_args!("{0}", __binding_2))
                                            })].into_iter();
                        let mut sub_args = rustc_errors::DiagArgMap::default();
                        sub_args.insert("kind".into(),
                            rustc_errors::IntoDiagArg::into_diag_arg(__binding_1,
                                &mut diag.long_ty_path));
                        sub_args.insert("suggestion".into(),
                            rustc_errors::IntoDiagArg::into_diag_arg(__binding_2,
                                &mut diag.long_ty_path));
                        let __message =
                            rustc_errors::format_diag_message(&rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("replace the use of the deprecated {$kind}")),
                                &sub_args);
                        diag.span_suggestions_with_style(__binding_0, __message,
                            __code_0, rustc_errors::Applicability::MachineApplicable,
                            rustc_errors::SuggestionStyle::ShowAlways);
                    }
                }
            }
        }
    };Subdiagnostic)]
99#[suggestion(
100    "replace the use of the deprecated {$kind}",
101    code = "{suggestion}",
102    style = "verbose",
103    applicability = "machine-applicable"
104)]
105pub struct DeprecationSuggestion {
106    #[primary_span]
107    pub span: Span,
108
109    pub kind: String,
110    pub suggestion: Symbol,
111}
112
113pub struct Deprecated {
114    pub sub: Option<DeprecationSuggestion>,
115
116    pub kind: String,
117    pub path: String,
118    pub note: Option<Symbol>,
119    pub since_kind: DeprecatedSinceKind,
120}
121
122impl<'a, G: EmissionGuarantee> rustc_errors::Diagnostic<'a, G> for Deprecated {
123    fn into_diag(
124        self,
125        dcx: rustc_errors::DiagCtxtHandle<'a>,
126        level: rustc_errors::Level,
127    ) -> Diag<'a, G> {
128        let Self { sub, kind, path, note, since_kind } = self;
129        let mut diag = Diag::new(dcx, level, match &since_kind {
130            DeprecatedSinceKind::InEffect => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("use of deprecated {$kind} `{$path}`{$has_note ->\n                    [true] : {$note}\n                    *[other] {\"\"}\n                }"))msg!(
131                "use of deprecated {$kind} `{$path}`{$has_note ->
132                    [true] : {$note}
133                    *[other] {\"\"}
134                }"
135            ),
136            DeprecatedSinceKind::InFuture => rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("use of {$kind} `{$path}` that will be deprecated in a future Rust version{$has_note ->\n                    [true] : {$note}\n                    *[other] {\"\"}\n                }"))msg!(
137                "use of {$kind} `{$path}` that will be deprecated in a future Rust version{$has_note ->
138                    [true] : {$note}
139                    *[other] {\"\"}
140                }"
141            ),
142            DeprecatedSinceKind::InVersion(_) => {
143                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("use of {$kind} `{$path}` that will be deprecated in future version {$version}{$has_note ->\n                        [true] : {$note}\n                        *[other] {\"\"}\n                    }"))msg!(
144                    "use of {$kind} `{$path}` that will be deprecated in future version {$version}{$has_note ->
145                        [true] : {$note}
146                        *[other] {\"\"}
147                    }"
148                )
149            }
150        })
151        .with_arg("kind", kind)
152        .with_arg("path", path);
153        if let DeprecatedSinceKind::InVersion(version) = since_kind {
154            diag.arg("version", version);
155        }
156        if let Some(note) = note {
157            diag.arg("has_note", true);
158            diag.arg("note", note);
159        } else {
160            diag.arg("has_note", false);
161        }
162        if let Some(sub) = sub {
163            diag.subdiagnostic(sub);
164        }
165        diag
166    }
167}
168
169fn deprecated_since_kind(is_in_effect: bool, since: DeprecatedSince) -> DeprecatedSinceKind {
170    if is_in_effect {
171        DeprecatedSinceKind::InEffect
172    } else {
173        match since {
174            DeprecatedSince::RustcVersion(version) => {
175                DeprecatedSinceKind::InVersion(version.to_string())
176            }
177            DeprecatedSince::Future => DeprecatedSinceKind::InFuture,
178            DeprecatedSince::NonStandard(_)
179            | DeprecatedSince::Unspecified
180            | DeprecatedSince::Err => {
181                {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("this deprecation is always in effect; {0:?}",
                since)));
}unreachable!("this deprecation is always in effect; {since:?}")
182            }
183        }
184    }
185}
186
187pub fn early_report_macro_deprecation(
188    lint_buffer: &mut LintBuffer,
189    depr: &Deprecation,
190    suggestion_span: Span,
191    node_id: NodeId,
192    path: String,
193) {
194    if suggestion_span.in_derive_expansion() {
195        return;
196    }
197
198    let is_in_effect = depr.is_in_effect();
199    let suggestion = depr.suggestion;
200    let note = depr.note.map(|ident| ident.name);
201    let since_kind = deprecated_since_kind(is_in_effect, depr.since);
202    lint_buffer.dyn_buffer_lint(
203        deprecation_lint(is_in_effect),
204        node_id,
205        suggestion_span,
206        move |dcx, level| {
207            let sub = suggestion.map(|suggestion| DeprecationSuggestion {
208                span: suggestion_span,
209                kind: "macro".to_owned(),
210                suggestion,
211            });
212
213            Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind }
214                .into_diag(dcx, level)
215        },
216    );
217}
218
219fn late_report_deprecation(
220    tcx: TyCtxt<'_>,
221    depr: &Deprecation,
222    span: Span,
223    method_span: Option<Span>,
224    hir_id: HirId,
225    def_id: DefId,
226) {
227    if span.in_derive_expansion() {
228        return;
229    }
230
231    let is_in_effect = depr.is_in_effect();
232    let lint = deprecation_lint(is_in_effect);
233
234    // Calculating message for lint involves calling `self.def_path_str`,
235    // which will by default invoke the expensive `visible_parent_map` query.
236    // Skip all that work if the lint is allowed anyway.
237    if tcx.lint_level_at_node(lint, hir_id).level == Level::Allow {
238        return;
239    }
240
241    let def_path = { let _guard = NoTrimmedGuard::new(); tcx.def_path_str(def_id) }with_no_trimmed_paths!(tcx.def_path_str(def_id));
242    let def_kind = tcx.def_descr(def_id);
243
244    let method_span = method_span.unwrap_or(span);
245    let suggestion =
246        if let hir::Node::Expr(_) = tcx.hir_node(hir_id) { depr.suggestion } else { None };
247    let diag = Deprecated {
248        sub: suggestion.map(|suggestion| DeprecationSuggestion {
249            span: method_span,
250            kind: def_kind.to_owned(),
251            suggestion,
252        }),
253        kind: def_kind.to_owned(),
254        path: def_path,
255        note: depr.note.map(|ident| ident.name),
256        since_kind: deprecated_since_kind(is_in_effect, depr.since),
257    };
258    tcx.emit_node_span_lint(lint, hir_id, method_span, diag);
259}
260
261/// Result of `TyCtxt::eval_stability`.
262pub enum EvalResult {
263    /// We can use the item because it is stable or we provided the
264    /// corresponding feature gate.
265    Allow,
266    /// We cannot use the item because it is unstable and we did not provide the
267    /// corresponding feature gate.
268    Deny {
269        feature: Symbol,
270        reason: Option<Symbol>,
271        issue: Option<NonZero<u32>>,
272        suggestion: Option<(Span, String, String, Applicability)>,
273    },
274    /// The item does not have the `#[stable]` or `#[unstable]` marker assigned.
275    Unmarked,
276}
277
278// See issue #83250.
279fn suggestion_for_allocator_api(
280    tcx: TyCtxt<'_>,
281    def_id: DefId,
282    span: Span,
283    feature: Symbol,
284) -> Option<(Span, String, String, Applicability)> {
285    if feature == sym::allocator_api {
286        if let Some(trait_) = tcx.opt_parent(def_id) {
287            if tcx.is_diagnostic_item(sym::Vec, trait_) {
288                let sm = tcx.sess.psess.source_map();
289                let inner_types = sm.span_extend_to_prev_char(span, '<', true);
290                if let Ok(snippet) = sm.span_to_snippet(inner_types) {
291                    return Some((
292                        inner_types,
293                        "consider wrapping the inner types in tuple".to_string(),
294                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("({0})", snippet))
    })format!("({snippet})"),
295                        Applicability::MaybeIncorrect,
296                    ));
297                }
298            }
299        }
300    }
301    None
302}
303
304/// An override option for eval_stability.
305pub enum AllowUnstable {
306    /// Don't emit an unstable error for the item
307    Yes,
308    /// Handle the item normally
309    No,
310}
311
312impl<'tcx> TyCtxt<'tcx> {
313    /// Evaluates the stability of an item.
314    ///
315    /// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding
316    /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
317    /// unstable feature otherwise.
318    ///
319    /// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been
320    /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
321    /// `id`.
322    pub fn eval_stability(
323        self,
324        def_id: DefId,
325        id: Option<HirId>,
326        span: Span,
327        method_span: Option<Span>,
328    ) -> EvalResult {
329        self.eval_stability_allow_unstable(def_id, id, span, method_span, AllowUnstable::No)
330    }
331
332    /// Evaluates the stability of an item.
333    ///
334    /// Returns `EvalResult::Allow` if the item is stable, or unstable but the corresponding
335    /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
336    /// unstable feature otherwise.
337    ///
338    /// If `id` is `Some(_)`, this function will also check if the item at `def_id` has been
339    /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
340    /// `id`.
341    ///
342    /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally.
343    pub fn eval_stability_allow_unstable(
344        self,
345        def_id: DefId,
346        id: Option<HirId>,
347        span: Span,
348        method_span: Option<Span>,
349        allow_unstable: AllowUnstable,
350    ) -> EvalResult {
351        // Deprecated attributes apply in-crate and cross-crate.
352        if let Some(id) = id {
353            if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
354                let parent_def_id = self.hir_get_parent_item(id);
355                let skip = self
356                    .lookup_deprecation_entry(parent_def_id.to_def_id())
357                    .is_some_and(|parent_depr| parent_depr.same_origin(&depr_entry));
358
359                // #[deprecated] doesn't emit a notice if we're not on the
360                // topmost deprecation. For example, if a struct is deprecated,
361                // the use of a field won't be linted.
362                //
363                // With #![staged_api], we want to emit down the whole
364                // hierarchy.
365                let depr_attr = &depr_entry.attr;
366                if !skip || depr_attr.is_since_rustc_version() {
367                    late_report_deprecation(self, depr_attr, span, method_span, id, def_id);
368                }
369            };
370        }
371
372        let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
373        if !is_staged_api {
374            return EvalResult::Allow;
375        }
376
377        // Only the cross-crate scenario matters when checking unstable APIs
378        let cross_crate = !def_id.is_local();
379        if !cross_crate {
380            return EvalResult::Allow;
381        }
382
383        let stability = self.lookup_stability(def_id);
384        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/stability.rs:384",
                        "rustc_middle::middle::stability", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/stability.rs"),
                        ::tracing_core::__macro_support::Option::Some(384u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::stability"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("stability: inspecting def_id={0:?} span={1:?} of stability={2:?}",
                                                    def_id, span, stability) as &dyn Value))])
            });
    } else { ; }
};debug!(
385            "stability: \
386                inspecting def_id={:?} span={:?} of stability={:?}",
387            def_id, span, stability
388        );
389
390        match stability {
391            Some(Stability {
392                level: hir::StabilityLevel::Unstable { reason, issue, implied_by, .. },
393                feature,
394                ..
395            }) => {
396                if span.allows_unstable(feature) {
397                    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/stability.rs:397",
                        "rustc_middle::middle::stability", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/stability.rs"),
                        ::tracing_core::__macro_support::Option::Some(397u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::stability"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("stability: skipping span={0:?} since it is internal",
                                                    span) as &dyn Value))])
            });
    } else { ; }
};debug!("stability: skipping span={:?} since it is internal", span);
398                    return EvalResult::Allow;
399                }
400                if self.features().enabled(feature) {
401                    return EvalResult::Allow;
402                }
403
404                // If this item was previously part of a now-stabilized feature which is still
405                // enabled (i.e. the user hasn't removed the attribute for the stabilized feature
406                // yet) then allow use of this item.
407                if let Some(implied_by) = implied_by
408                    && self.features().enabled(implied_by)
409                {
410                    return EvalResult::Allow;
411                }
412
413                // When we're compiling the compiler itself we may pull in
414                // crates from crates.io, but those crates may depend on other
415                // crates also pulled in from crates.io. We want to ideally be
416                // able to compile everything without requiring upstream
417                // modifications, so in the case that this looks like a
418                // `rustc_private` crate (e.g., a compiler crate) and we also have
419                // the `-Z force-unstable-if-unmarked` flag present (we're
420                // compiling a compiler crate), then let this missing feature
421                // annotation slide.
422                if feature == sym::rustc_private
423                    && issue == NonZero::new(27812)
424                    && self.sess.opts.unstable_opts.force_unstable_if_unmarked
425                {
426                    return EvalResult::Allow;
427                }
428
429                if #[allow(non_exhaustive_omitted_patterns)] match allow_unstable {
    AllowUnstable::Yes => true,
    _ => false,
}matches!(allow_unstable, AllowUnstable::Yes) {
430                    return EvalResult::Allow;
431                }
432
433                let suggestion = suggestion_for_allocator_api(self, def_id, span, feature);
434                EvalResult::Deny { feature, reason: reason.to_opt_reason(), issue, suggestion }
435            }
436            Some(_) => {
437                // Stable APIs are always ok to call and deprecated APIs are
438                // handled by the lint emitting logic above.
439                EvalResult::Allow
440            }
441            None => EvalResult::Unmarked,
442        }
443    }
444
445    /// Evaluates the default-impl stability of an item.
446    ///
447    /// Returns `EvalResult::Allow` if the item's default implementation is stable, or unstable but the corresponding
448    /// `#![feature]` has been provided. Returns `EvalResult::Deny` which describes the offending
449    /// unstable feature otherwise.
450    pub fn eval_default_body_stability(self, def_id: DefId, span: Span) -> EvalResult {
451        let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
452        if !is_staged_api {
453            return EvalResult::Allow;
454        }
455
456        // Only the cross-crate scenario matters when checking unstable APIs
457        let cross_crate = !def_id.is_local();
458        if !cross_crate {
459            return EvalResult::Allow;
460        }
461
462        let stability = self.lookup_default_body_stability(def_id);
463        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/stability.rs:463",
                        "rustc_middle::middle::stability", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/stability.rs"),
                        ::tracing_core::__macro_support::Option::Some(463u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::stability"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("body stability: inspecting def_id={0:?} span={1:?} of stability={2:?}",
                                                    def_id, span, stability) as &dyn Value))])
            });
    } else { ; }
};debug!(
464            "body stability: inspecting def_id={def_id:?} span={span:?} of stability={stability:?}"
465        );
466
467        match stability {
468            Some(DefaultBodyStability {
469                level: hir::StabilityLevel::Unstable { reason, issue, .. },
470                feature,
471            }) => {
472                if span.allows_unstable(feature) {
473                    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/stability.rs:473",
                        "rustc_middle::middle::stability", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/stability.rs"),
                        ::tracing_core::__macro_support::Option::Some(473u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::stability"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("body stability: skipping span={0:?} since it is internal",
                                                    span) as &dyn Value))])
            });
    } else { ; }
};debug!("body stability: skipping span={:?} since it is internal", span);
474                    return EvalResult::Allow;
475                }
476                if self.features().enabled(feature) {
477                    return EvalResult::Allow;
478                }
479
480                EvalResult::Deny {
481                    feature,
482                    reason: reason.to_opt_reason(),
483                    issue,
484                    suggestion: None,
485                }
486            }
487            Some(_) => {
488                // Stable APIs are always ok to call
489                EvalResult::Allow
490            }
491            None => EvalResult::Unmarked,
492        }
493    }
494
495    /// Checks if an item is stable or error out.
496    ///
497    /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
498    /// exist, emits an error.
499    ///
500    /// This function will also check if the item is deprecated.
501    /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted.
502    ///
503    /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature.
504    pub fn check_stability(
505        self,
506        def_id: DefId,
507        id: Option<HirId>,
508        span: Span,
509        method_span: Option<Span>,
510    ) -> bool {
511        self.check_stability_allow_unstable(def_id, id, span, method_span, AllowUnstable::No)
512    }
513
514    /// Checks if an item is stable or error out.
515    ///
516    /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not
517    /// exist, emits an error.
518    ///
519    /// This function will also check if the item is deprecated.
520    /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted.
521    ///
522    /// Pass `AllowUnstable::Yes` to `allow_unstable` to force an unstable item to be allowed. Deprecation warnings will be emitted normally.
523    ///
524    /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature.
525    pub fn check_stability_allow_unstable(
526        self,
527        def_id: DefId,
528        id: Option<HirId>,
529        span: Span,
530        method_span: Option<Span>,
531        allow_unstable: AllowUnstable,
532    ) -> bool {
533        self.check_optional_stability(
534            def_id,
535            id,
536            span,
537            method_span,
538            allow_unstable,
539            |span, def_id| {
540                // The API could be uncallable for other reasons, for example when a private module
541                // was referenced.
542                self.dcx().span_delayed_bug(span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("encountered unmarked API: {0:?}",
                def_id))
    })format!("encountered unmarked API: {def_id:?}"));
543            },
544        )
545    }
546
547    /// Like `check_stability`, except that we permit items to have custom behaviour for
548    /// missing stability attributes (not necessarily just emit a `bug!`). This is necessary
549    /// for default generic parameters, which only have stability attributes if they were
550    /// added after the type on which they're defined.
551    ///
552    /// Returns `true` if item is allowed aka, stable or unstable under an enabled feature.
553    pub fn check_optional_stability(
554        self,
555        def_id: DefId,
556        id: Option<HirId>,
557        span: Span,
558        method_span: Option<Span>,
559        allow_unstable: AllowUnstable,
560        unmarked: impl FnOnce(Span, DefId),
561    ) -> bool {
562        let eval_result =
563            self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable);
564        let is_allowed = #[allow(non_exhaustive_omitted_patterns)] match eval_result {
    EvalResult::Allow => true,
    _ => false,
}matches!(eval_result, EvalResult::Allow);
565        match eval_result {
566            EvalResult::Allow => {}
567            EvalResult::Deny { feature, reason, issue, suggestion } => report_unstable(
568                self.sess,
569                feature,
570                reason,
571                issue,
572                suggestion,
573                span,
574                UnstableKind::Regular,
575            ),
576            EvalResult::Unmarked => unmarked(span, def_id),
577        }
578
579        is_allowed
580    }
581
582    /// This function is analogous to `check_optional_stability` but with the logic in
583    /// `eval_stability_allow_unstable` inlined, and which operating on const stability
584    /// instead of regular stability.
585    ///
586    /// This enforces *syntactical* const stability of const traits. In other words,
587    /// it enforces the ability to name `[const]`/`const` traits in trait bounds in various
588    /// syntax positions in HIR (including in the trait of an impl header).
589    pub fn check_const_stability(self, def_id: DefId, span: Span, const_kw_span: Span) {
590        let is_staged_api = self.lookup_stability(def_id.krate.as_def_id()).is_some();
591        if !is_staged_api {
592            return;
593        }
594
595        // Only the cross-crate scenario matters when checking unstable APIs
596        let cross_crate = !def_id.is_local();
597        if !cross_crate {
598            return;
599        }
600
601        let stability = self.lookup_const_stability(def_id);
602        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/stability.rs:602",
                        "rustc_middle::middle::stability", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/stability.rs"),
                        ::tracing_core::__macro_support::Option::Some(602u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::stability"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("stability: inspecting def_id={0:?} span={1:?} of stability={2:?}",
                                                    def_id, span, stability) as &dyn Value))])
            });
    } else { ; }
};debug!(
603            "stability: \
604                inspecting def_id={:?} span={:?} of stability={:?}",
605            def_id, span, stability
606        );
607
608        match stability {
609            Some(ConstStability {
610                level: hir::StabilityLevel::Unstable { reason, issue, implied_by, .. },
611                feature,
612                ..
613            }) => {
614                if span.allows_unstable(feature) {
615                    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_middle/src/middle/stability.rs:615",
                        "rustc_middle::middle::stability", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_middle/src/middle/stability.rs"),
                        ::tracing_core::__macro_support::Option::Some(615u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_middle::middle::stability"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("body stability: skipping span={0:?} since it is internal",
                                                    span) as &dyn Value))])
            });
    } else { ; }
};debug!("body stability: skipping span={:?} since it is internal", span);
616                    return;
617                }
618                if self.features().enabled(feature) {
619                    return;
620                }
621
622                // If this item was previously part of a now-stabilized feature which is still
623                // enabled (i.e. the user hasn't removed the attribute for the stabilized feature
624                // yet) then allow use of this item.
625                if let Some(implied_by) = implied_by
626                    && self.features().enabled(implied_by)
627                {
628                    return;
629                }
630
631                report_unstable(
632                    self.sess,
633                    feature,
634                    reason.to_opt_reason(),
635                    issue,
636                    None,
637                    span,
638                    UnstableKind::Const(const_kw_span),
639                );
640            }
641            Some(_) | None => {}
642        }
643    }
644
645    pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
646        self.lookup_deprecation_entry(id).map(|depr| depr.attr)
647    }
648}