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