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