Skip to main content

rustc_const_eval/check_consts/
ops.rs

1//! Concrete error types for all operations which may be invalid in a certain const context.
2
3use hir::{ConstContext, LangItem};
4use rustc_errors::codes::*;
5use rustc_errors::{Applicability, Diag, MultiSpan, msg};
6use rustc_hir as hir;
7use rustc_hir::def_id::DefId;
8use rustc_infer::infer::TyCtxtInferExt;
9use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
10use rustc_middle::mir::CallSource;
11use rustc_middle::span_bug;
12use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
13use rustc_middle::ty::{
14    self, AssocContainer, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef,
15    Ty, suggest_constraining_type_param,
16};
17use rustc_session::errors::add_feature_diagnostics;
18use rustc_span::{BytePos, Pos, Span, Symbol, sym};
19use rustc_trait_selection::error_reporting::traits::call_kind::{
20    CallDesugaringKind, CallKind, call_kind,
21};
22use rustc_trait_selection::traits::SelectionContext;
23use tracing::debug;
24
25use super::ConstCx;
26use crate::errors;
27
28#[derive(#[automatically_derived]
impl ::core::clone::Clone for Status {
    #[inline]
    fn clone(&self) -> Status {
        let _: ::core::clone::AssertParamIsClone<Symbol>;
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Status { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for Status {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Status::Unstable {
                gate: __self_0,
                gate_already_checked: __self_1,
                safe_to_expose_on_stable: __self_2,
                is_function_call: __self_3 } =>
                ::core::fmt::Formatter::debug_struct_field4_finish(f,
                    "Unstable", "gate", __self_0, "gate_already_checked",
                    __self_1, "safe_to_expose_on_stable", __self_2,
                    "is_function_call", &__self_3),
            Status::Forbidden =>
                ::core::fmt::Formatter::write_str(f, "Forbidden"),
        }
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for Status {
    #[inline]
    fn eq(&self, other: &Status) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (Status::Unstable {
                    gate: __self_0,
                    gate_already_checked: __self_1,
                    safe_to_expose_on_stable: __self_2,
                    is_function_call: __self_3 }, Status::Unstable {
                    gate: __arg1_0,
                    gate_already_checked: __arg1_1,
                    safe_to_expose_on_stable: __arg1_2,
                    is_function_call: __arg1_3 }) =>
                    __self_1 == __arg1_1 && __self_2 == __arg1_2 &&
                            __self_3 == __arg1_3 && __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for Status {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Symbol>;
        let _: ::core::cmp::AssertParamIsEq<bool>;
    }
}Eq)]
29pub enum Status {
30    Unstable {
31        /// The feature that must be enabled to use this operation.
32        gate: Symbol,
33        /// Whether the feature gate was already checked (because the logic is a bit more
34        /// complicated than just checking a single gate).
35        gate_already_checked: bool,
36        /// Whether it is allowed to use this operation from stable `const fn`.
37        /// This will usually be `false`.
38        safe_to_expose_on_stable: bool,
39        /// We indicate whether this is a function call, since we can use targeted
40        /// diagnostics for "callee is not safe to expose om stable".
41        is_function_call: bool,
42    },
43    Forbidden,
44}
45
46#[derive(#[automatically_derived]
impl ::core::clone::Clone for DiagImportance {
    #[inline]
    fn clone(&self) -> DiagImportance { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for DiagImportance { }Copy)]
47pub enum DiagImportance {
48    /// An operation that must be removed for const-checking to pass.
49    Primary,
50
51    /// An operation that causes const-checking to fail, but is usually a side-effect of a `Primary` operation elsewhere.
52    Secondary,
53}
54
55/// An operation that is *not allowed* in a const context.
56pub trait NonConstOp<'tcx>: std::fmt::Debug {
57    /// Returns an enum indicating whether this operation can be enabled with a feature gate.
58    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
59        Status::Forbidden
60    }
61
62    fn importance(&self) -> DiagImportance {
63        DiagImportance::Primary
64    }
65
66    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx>;
67}
68
69/// A function call where the callee is a pointer.
70#[derive(#[automatically_derived]
impl ::core::fmt::Debug for FnCallIndirect {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "FnCallIndirect")
    }
}Debug)]
71pub(crate) struct FnCallIndirect;
72impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
73    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
74        ccx.dcx().create_err(errors::UnallowedFnPointerCall { span, kind: ccx.const_kind() })
75    }
76}
77
78/// A c-variadic function call.
79#[derive(#[automatically_derived]
impl ::core::fmt::Debug for FnCallCVariadic {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "FnCallCVariadic")
    }
}Debug)]
80pub(crate) struct FnCallCVariadic;
81impl<'tcx> NonConstOp<'tcx> for FnCallCVariadic {
82    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
83        Status::Unstable {
84            gate: sym::const_c_variadic,
85            gate_already_checked: false,
86            safe_to_expose_on_stable: false,
87            is_function_call: true,
88        }
89    }
90
91    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
92        ccx.tcx.sess.create_feature_err(
93            errors::NonConstCVariadicCall { span, kind: ccx.const_kind() },
94            sym::const_c_variadic,
95        )
96    }
97}
98
99/// A call to a function that is in a trait, or has trait bounds that make it conditionally-const.
100#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for ConditionallyConstCall<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f,
            "ConditionallyConstCall", "callee", &self.callee, "args",
            &self.args, "span", &self.span, "call_source", &&self.call_source)
    }
}Debug)]
101pub(crate) struct ConditionallyConstCall<'tcx> {
102    pub callee: DefId,
103    pub args: GenericArgsRef<'tcx>,
104    pub span: Span,
105    pub call_source: CallSource,
106}
107
108impl<'tcx> NonConstOp<'tcx> for ConditionallyConstCall<'tcx> {
109    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
110        // We use the `const_trait_impl` gate for all conditionally-const calls.
111        Status::Unstable {
112            gate: sym::const_trait_impl,
113            gate_already_checked: false,
114            safe_to_expose_on_stable: false,
115            // We don't want the "mark the callee as `#[rustc_const_stable_indirect]`" hint
116            is_function_call: false,
117        }
118    }
119
120    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
121        let mut diag = build_error_for_const_call(
122            ccx,
123            self.callee,
124            self.args,
125            self.span,
126            self.call_source,
127            "conditionally",
128            |_, _, _| {},
129        );
130
131        // Override code and mention feature.
132        diag.code(E0658);
133        add_feature_diagnostics(&mut diag, ccx.tcx.sess, sym::const_trait_impl);
134
135        diag
136    }
137}
138
139/// A function call where the callee is not marked as `const`.
140#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for FnCallNonConst<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field4_finish(f,
            "FnCallNonConst", "callee", &self.callee, "args", &self.args,
            "span", &self.span, "call_source", &&self.call_source)
    }
}Debug, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for FnCallNonConst<'tcx> {
    #[inline]
    fn clone(&self) -> FnCallNonConst<'tcx> {
        let _: ::core::clone::AssertParamIsClone<DefId>;
        let _: ::core::clone::AssertParamIsClone<GenericArgsRef<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<Span>;
        let _: ::core::clone::AssertParamIsClone<CallSource>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for FnCallNonConst<'tcx> { }Copy)]
141pub(crate) struct FnCallNonConst<'tcx> {
142    pub callee: DefId,
143    pub args: GenericArgsRef<'tcx>,
144    pub span: Span,
145    pub call_source: CallSource,
146}
147
148impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
149    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
150        let tcx = ccx.tcx;
151        let caller = ccx.def_id();
152
153        let mut err = build_error_for_const_call(
154            ccx,
155            self.callee,
156            self.args,
157            self.span,
158            self.call_source,
159            "non",
160            |err, self_ty, trait_id| {
161                // FIXME(const_trait_impl): Do we need any of this on the non-const codepath?
162
163                let trait_ref = TraitRef::from_assoc(tcx, trait_id, self.args);
164
165                match self_ty.kind() {
166                    Param(param_ty) => {
167                        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_const_eval/src/check_consts/ops.rs:167",
                        "rustc_const_eval::check_consts::ops",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/check_consts/ops.rs"),
                        ::tracing_core::__macro_support::Option::Some(167u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::check_consts::ops"),
                        ::tracing_core::field::FieldSet::new(&["param_ty"],
                            ::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(&debug(&param_ty)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?param_ty);
168                        if let Some(generics) = tcx.hir_node_by_def_id(caller).generics() {
169                            let constraint = {
    let _guard = NoTrimmedGuard::new();
    ::alloc::__export::must_use({
            ::alloc::fmt::format(format_args!("[const] {0}",
                    trait_ref.print_trait_sugared()))
        })
}with_no_trimmed_paths!(format!(
170                                "[const] {}",
171                                trait_ref.print_trait_sugared(),
172                            ));
173                            suggest_constraining_type_param(
174                                tcx,
175                                generics,
176                                err,
177                                param_ty.name.as_str(),
178                                &constraint,
179                                Some(trait_ref.def_id),
180                                None,
181                            );
182                        }
183                    }
184                    ty::Adt(..) => {
185                        let (infcx, param_env) =
186                            tcx.infer_ctxt().build_with_typing_env(ccx.typing_env);
187                        let obligation =
188                            Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
189                        let mut selcx = SelectionContext::new(&infcx);
190                        let implsrc = selcx.select(&obligation);
191                        if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
192                            // FIXME(const_trait_impl) revisit this
193                            if !tcx.is_const_trait_impl(data.impl_def_id) {
194                                let span = tcx.def_span(data.impl_def_id);
195                                err.subdiagnostic(errors::NonConstImplNote { span });
196                            }
197                        }
198                    }
199                    _ => {}
200                }
201            },
202        );
203
204        if let ConstContext::Static(_) = ccx.const_kind() {
205            err.note(rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`"))msg!(
206                "consider wrapping this expression in `std::sync::LazyLock::new(|| ...)`"
207            ));
208        }
209
210        err
211    }
212}
213
214/// Build an error message reporting that a function call is not const (or only
215/// conditionally const). In case that this call is desugared (like an operator
216/// or sugar from something like a `for` loop), try to build a better error message
217/// that doesn't call it a method.
218fn build_error_for_const_call<'tcx>(
219    ccx: &ConstCx<'_, 'tcx>,
220    callee: DefId,
221    args: ty::GenericArgsRef<'tcx>,
222    span: Span,
223    call_source: CallSource,
224    non_or_conditionally: &'static str,
225    note_trait_if_possible: impl FnOnce(&mut Diag<'tcx>, Ty<'tcx>, DefId),
226) -> Diag<'tcx> {
227    let tcx = ccx.tcx;
228
229    let call_kind =
230        call_kind(tcx, ccx.typing_env, callee, args, span, call_source.from_hir_call(), None);
231
232    {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_const_eval/src/check_consts/ops.rs:232",
                        "rustc_const_eval::check_consts::ops",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/check_consts/ops.rs"),
                        ::tracing_core::__macro_support::Option::Some(232u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::check_consts::ops"),
                        ::tracing_core::field::FieldSet::new(&["call_kind"],
                            ::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(&debug(&call_kind)
                                            as &dyn Value))])
            });
    } else { ; }
};debug!(?call_kind);
233
234    let mut err = match call_kind {
235        CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
236            macro_rules! error {
237                ($err:ident) => {
238                    tcx.dcx().create_err(errors::$err {
239                        span,
240                        ty: self_ty,
241                        kind: ccx.const_kind(),
242                        non_or_conditionally,
243                    })
244                };
245            }
246
247            // Don't point at the trait if this is a desugaring...
248            // FIXME(const_trait_impl): we could perhaps do this for `Iterator`.
249            match kind {
250                CallDesugaringKind::ForLoopIntoIter | CallDesugaringKind::ForLoopNext => {
251                    tcx.dcx().create_err(errors::NonConstForLoopIntoIter {
        span,
        ty: self_ty,
        kind: ccx.const_kind(),
        non_or_conditionally,
    })error!(NonConstForLoopIntoIter)
252                }
253                CallDesugaringKind::QuestionBranch => {
254                    tcx.dcx().create_err(errors::NonConstQuestionBranch {
        span,
        ty: self_ty,
        kind: ccx.const_kind(),
        non_or_conditionally,
    })error!(NonConstQuestionBranch)
255                }
256                CallDesugaringKind::QuestionFromResidual => {
257                    tcx.dcx().create_err(errors::NonConstQuestionFromResidual {
        span,
        ty: self_ty,
        kind: ccx.const_kind(),
        non_or_conditionally,
    })error!(NonConstQuestionFromResidual)
258                }
259                CallDesugaringKind::TryBlockFromOutput => {
260                    tcx.dcx().create_err(errors::NonConstTryBlockFromOutput {
        span,
        ty: self_ty,
        kind: ccx.const_kind(),
        non_or_conditionally,
    })error!(NonConstTryBlockFromOutput)
261                }
262                CallDesugaringKind::Await => {
263                    tcx.dcx().create_err(errors::NonConstAwait {
        span,
        ty: self_ty,
        kind: ccx.const_kind(),
        non_or_conditionally,
    })error!(NonConstAwait)
264                }
265            }
266        }
267        CallKind::FnCall { fn_trait_id, self_ty } => {
268            let kind = ccx.const_kind();
269            let note = match self_ty.kind() {
270                FnDef(def_id, ..) => {
271                    let span = tcx.def_span(*def_id);
272                    if ccx.tcx.is_const_fn(*def_id) {
273                        ::rustc_middle::util::bug::span_bug_fmt(span,
    format_args!("calling const FnDef errored when it shouldn\'t"));span_bug!(span, "calling const FnDef errored when it shouldn't");
274                    }
275
276                    Some(errors::NonConstClosureNote::FnDef { span })
277                }
278                FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr { kind }),
279                Closure(..) => Some(errors::NonConstClosureNote::Closure { kind }),
280                _ => None,
281            };
282
283            let mut err = tcx.dcx().create_err(errors::NonConstClosure {
284                span,
285                kind: ccx.const_kind(),
286                note,
287                non_or_conditionally,
288            });
289
290            note_trait_if_possible(&mut err, self_ty, fn_trait_id);
291            err
292        }
293        CallKind::Operator { trait_id, self_ty, .. } => {
294            let mut err = if let CallSource::MatchCmp = call_source {
295                tcx.dcx().create_err(errors::NonConstMatchEq {
296                    span,
297                    kind: ccx.const_kind(),
298                    ty: self_ty,
299                    non_or_conditionally,
300                })
301            } else {
302                let mut sugg = None;
303
304                if ccx.tcx.is_lang_item(trait_id, LangItem::PartialEq) {
305                    match (args[0].kind(), args[1].kind()) {
306                        (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
307                            if self_ty == rhs_ty
308                                && self_ty.is_ref()
309                                && self_ty.peel_refs().is_primitive() =>
310                        {
311                            let mut num_refs = 0;
312                            let mut tmp_ty = self_ty;
313                            while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
314                                num_refs += 1;
315                                tmp_ty = *inner_ty;
316                            }
317                            let deref = "*".repeat(num_refs);
318
319                            if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span)
320                                && let Some(eq_idx) = call_str.find("==")
321                                && let Some(rhs_idx) =
322                                    call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
323                            {
324                                let rhs_pos = span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
325                                let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
326                                sugg = Some(errors::ConsiderDereferencing {
327                                    deref,
328                                    span: span.shrink_to_lo(),
329                                    rhs_span,
330                                });
331                            }
332                        }
333                        _ => {}
334                    }
335                }
336                tcx.dcx().create_err(errors::NonConstOperator {
337                    span,
338                    kind: ccx.const_kind(),
339                    sugg,
340                    non_or_conditionally,
341                })
342            };
343
344            note_trait_if_possible(&mut err, self_ty, trait_id);
345            err
346        }
347        CallKind::DerefCoercion { deref_target_span, deref_target_ty, self_ty } => {
348            // Check first whether the source is accessible (issue #87060)
349            let target = if let Some(deref_target_span) = deref_target_span
350                && tcx.sess.source_map().is_span_accessible(deref_target_span)
351            {
352                Some(deref_target_span)
353            } else {
354                None
355            };
356
357            let mut err = tcx.dcx().create_err(errors::NonConstDerefCoercion {
358                span,
359                ty: self_ty,
360                kind: ccx.const_kind(),
361                target_ty: deref_target_ty,
362                deref_target: target,
363                non_or_conditionally,
364            });
365
366            note_trait_if_possible(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, span));
367            err
368        }
369        _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::FmtArgumentsNew) => {
370            ccx.dcx().create_err(errors::NonConstFmtMacroCall {
371                span,
372                kind: ccx.const_kind(),
373                non_or_conditionally,
374            })
375        }
376        _ => {
377            let def_descr = ccx.tcx.def_descr(callee);
378            let mut err = ccx.dcx().create_err(errors::NonConstFnCall {
379                span,
380                def_descr,
381                def_path_str: ccx.tcx.def_path_str_with_args(callee, args),
382                kind: ccx.const_kind(),
383                non_or_conditionally,
384            });
385            if let Some(item) = ccx.tcx.opt_associated_item(callee) {
386                if let AssocContainer::Trait = item.container
387                    && let parent = item.container_id(ccx.tcx)
388                    && !ccx.tcx.is_const_trait(parent)
389                {
390                    let assoc_span = ccx.tcx.def_span(callee);
391                    let assoc_name = ccx.tcx.item_name(callee);
392                    let mut span: MultiSpan = ccx.tcx.def_span(parent).into();
393                    span.push_span_label(assoc_span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("this {0} is not const", def_descr))
    })format!("this {def_descr} is not const"));
394                    let trait_descr = ccx.tcx.def_descr(parent);
395                    let trait_span = ccx.tcx.def_span(parent);
396                    let trait_name = ccx.tcx.item_name(parent);
397                    span.push_span_label(trait_span, ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("this {0} is not const",
                trait_descr))
    })format!("this {trait_descr} is not const"));
398                    err.span_note(
399                        span,
400                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} `{1}` is not const because {2} `{3}` is not const",
                def_descr, assoc_name, trait_descr, trait_name))
    })format!(
401                            "{def_descr} `{assoc_name}` is not const because {trait_descr} \
402                            `{trait_name}` is not const",
403                        ),
404                    );
405                    if let Some(parent) = parent.as_local()
406                        && ccx.tcx.sess.is_nightly_build()
407                    {
408                        if !ccx.tcx.features().const_trait_impl() {
409                            err.help(
410                                "add `#![feature(const_trait_impl)]` to the crate attributes to \
411                                 enable const traits",
412                            );
413                        }
414                        let span = ccx.tcx.hir_expect_item(parent).vis_span;
415                        let span = ccx.tcx.sess.source_map().span_extend_while_whitespace(span);
416                        err.span_suggestion_verbose(
417                            span.shrink_to_hi(),
418                            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("consider making trait `{0}` const",
                trait_name))
    })format!("consider making trait `{trait_name}` const"),
419                            "const ".to_owned(),
420                            Applicability::MaybeIncorrect,
421                        );
422                    } else if !ccx.tcx.sess.is_nightly_build() {
423                        err.help("const traits are not yet supported on stable Rust");
424                    }
425                }
426            } else if !#[allow(non_exhaustive_omitted_patterns)] match ccx.tcx.constness(callee) {
    hir::Constness::Const { always: false } => true,
    _ => false,
}matches!(ccx.tcx.constness(callee), hir::Constness::Const { always: false })
427            {
428                let name = ccx.tcx.item_name(callee);
429                err.span_note(
430                    ccx.tcx.def_span(callee),
431                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} `{1}` is not const", def_descr,
                name))
    })format!("{def_descr} `{name}` is not const"),
432                );
433            }
434            err
435        }
436    };
437
438    err.note(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("calls in {0}s are limited to constant functions, tuple structs and tuple variants",
                ccx.const_kind()))
    })format!(
439        "calls in {}s are limited to constant functions, tuple structs and tuple variants",
440        ccx.const_kind(),
441    ));
442
443    err
444}
445
446/// A call to an `#[unstable]` const fn, `#[rustc_const_unstable]` function or trait.
447///
448/// Contains the name of the feature that would allow the use of this function/trait.
449#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CallUnstable {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field5_finish(f, "CallUnstable",
            "def_id", &self.def_id, "feature", &self.feature,
            "feature_enabled", &self.feature_enabled,
            "safe_to_expose_on_stable", &self.safe_to_expose_on_stable,
            "is_function_call", &&self.is_function_call)
    }
}Debug)]
450pub(crate) struct CallUnstable {
451    pub def_id: DefId,
452    pub feature: Symbol,
453    /// If this is true, then the feature is enabled, but we need to still check if it is safe to
454    /// expose on stable.
455    pub feature_enabled: bool,
456    pub safe_to_expose_on_stable: bool,
457    /// true if `def_id` is the function we are calling, false if `def_id` is an unstable trait.
458    pub is_function_call: bool,
459}
460
461impl<'tcx> NonConstOp<'tcx> for CallUnstable {
462    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
463        Status::Unstable {
464            gate: self.feature,
465            gate_already_checked: self.feature_enabled,
466            safe_to_expose_on_stable: self.safe_to_expose_on_stable,
467            is_function_call: self.is_function_call,
468        }
469    }
470
471    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
472        if !!self.feature_enabled {
    ::core::panicking::panic("assertion failed: !self.feature_enabled")
};assert!(!self.feature_enabled);
473        let mut err = if self.is_function_call {
474            ccx.dcx().create_err(errors::UnstableConstFn {
475                span,
476                def_path: ccx.tcx.def_path_str(self.def_id),
477            })
478        } else {
479            ccx.dcx().create_err(errors::UnstableConstTrait {
480                span,
481                def_path: ccx.tcx.def_path_str(self.def_id),
482            })
483        };
484        ccx.tcx.disabled_nightly_features(&mut err, [(String::new(), self.feature)]);
485        err
486    }
487}
488
489/// A call to an intrinsic that is just not const-callable at all.
490#[derive(#[automatically_derived]
impl ::core::fmt::Debug for IntrinsicNonConst {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "IntrinsicNonConst", "name", &&self.name)
    }
}Debug)]
491pub(crate) struct IntrinsicNonConst {
492    pub name: Symbol,
493}
494
495impl<'tcx> NonConstOp<'tcx> for IntrinsicNonConst {
496    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
497        ccx.dcx().create_err(errors::NonConstIntrinsic {
498            span,
499            name: self.name,
500            kind: ccx.const_kind(),
501        })
502    }
503}
504
505/// A call to an intrinsic that is just not const-callable at all.
506#[derive(#[automatically_derived]
impl ::core::fmt::Debug for IntrinsicUnstable {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f,
            "IntrinsicUnstable", "name", &self.name, "feature", &self.feature,
            "const_stable_indirect", &&self.const_stable_indirect)
    }
}Debug)]
507pub(crate) struct IntrinsicUnstable {
508    pub name: Symbol,
509    pub feature: Symbol,
510    pub const_stable_indirect: bool,
511}
512
513impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
514    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
515        Status::Unstable {
516            gate: self.feature,
517            gate_already_checked: false,
518            safe_to_expose_on_stable: self.const_stable_indirect,
519            // We do *not* want to suggest to mark the intrinsic as `const_stable_indirect`,
520            // that's not a trivial change!
521            is_function_call: false,
522        }
523    }
524
525    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
526        ccx.dcx().create_err(errors::UnstableIntrinsic {
527            span,
528            name: self.name,
529            feature: self.feature,
530            suggestion: ccx.tcx.crate_level_attribute_injection_span(),
531        })
532    }
533}
534
535#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Coroutine {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Coroutine",
            &&self.0)
    }
}Debug)]
536pub(crate) struct Coroutine(pub hir::CoroutineKind);
537impl<'tcx> NonConstOp<'tcx> for Coroutine {
538    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
539        match self.0 {
540            hir::CoroutineKind::Desugared(
541                hir::CoroutineDesugaring::Async,
542                hir::CoroutineSource::Block,
543            )
544            // FIXME(coroutines): eventually we want to gate const coroutine coroutines behind a
545            // different feature.
546            | hir::CoroutineKind::Coroutine(_) => Status::Unstable {
547                gate: sym::const_async_blocks,
548                gate_already_checked: false,
549                safe_to_expose_on_stable: false,
550                is_function_call: false,
551            },
552            _ => Status::Forbidden,
553        }
554    }
555
556    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
557        let msg = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0} are not allowed in {1}s",
                self.0.to_plural_string(), ccx.const_kind()))
    })format!("{} are not allowed in {}s", self.0.to_plural_string(), ccx.const_kind());
558        if let Status::Unstable { gate, .. } = self.status_in_item(ccx) {
559            ccx.tcx.sess.create_feature_err(errors::UnallowedOpInConstContext { span, msg }, gate)
560        } else {
561            ccx.dcx().create_err(errors::UnallowedOpInConstContext { span, msg })
562        }
563    }
564}
565
566#[derive(#[automatically_derived]
impl ::core::fmt::Debug for InlineAsm {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "InlineAsm")
    }
}Debug)]
567pub(crate) struct InlineAsm;
568impl<'tcx> NonConstOp<'tcx> for InlineAsm {
569    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
570        ccx.dcx().create_err(errors::UnallowedInlineAsm { span, kind: ccx.const_kind() })
571    }
572}
573
574#[derive(#[automatically_derived]
impl<'tcx> ::core::fmt::Debug for LiveDrop<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f, "LiveDrop",
            "dropped_at", &self.dropped_at, "dropped_ty", &self.dropped_ty,
            "needs_non_const_drop", &&self.needs_non_const_drop)
    }
}Debug)]
575pub(crate) struct LiveDrop<'tcx> {
576    pub dropped_at: Span,
577    pub dropped_ty: Ty<'tcx>,
578    pub needs_non_const_drop: bool,
579}
580impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
581    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
582        if self.needs_non_const_drop {
583            Status::Forbidden
584        } else {
585            Status::Unstable {
586                gate: sym::const_destruct,
587                gate_already_checked: false,
588                safe_to_expose_on_stable: false,
589                is_function_call: false,
590            }
591        }
592    }
593
594    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
595        if self.needs_non_const_drop {
596            ccx.dcx().create_err(errors::LiveDrop {
597                span,
598                dropped_ty: self.dropped_ty,
599                kind: ccx.const_kind(),
600                dropped_at: self.dropped_at,
601            })
602        } else {
603            ccx.tcx.sess.create_feature_err(
604                errors::LiveDrop {
605                    span,
606                    dropped_ty: self.dropped_ty,
607                    kind: ccx.const_kind(),
608                    dropped_at: self.dropped_at,
609                },
610                sym::const_destruct,
611            )
612        }
613    }
614}
615
616#[derive(#[automatically_derived]
impl ::core::fmt::Debug for EscapingCellBorrow {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "EscapingCellBorrow")
    }
}Debug)]
617/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow might escape to
618/// the final value of the constant, and thus we cannot allow this (for now). We may allow
619/// it in the future for static items.
620pub(crate) struct EscapingCellBorrow;
621impl<'tcx> NonConstOp<'tcx> for EscapingCellBorrow {
622    fn importance(&self) -> DiagImportance {
623        // Most likely the code will try to do mutation with these borrows, which
624        // triggers its own errors. Only show this one if that does not happen.
625        DiagImportance::Secondary
626    }
627    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
628        ccx.dcx().create_err(errors::InteriorMutableBorrowEscaping { span, kind: ccx.const_kind() })
629    }
630}
631
632#[derive(#[automatically_derived]
impl ::core::fmt::Debug for EscapingMutBorrow {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "EscapingMutBorrow")
    }
}Debug)]
633/// This op is for `&mut` borrows in the trailing expression of a constant
634/// which uses the "enclosing scopes rule" to leak its locals into anonymous
635/// static or const items.
636pub(crate) struct EscapingMutBorrow;
637
638impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
639    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
640        Status::Forbidden
641    }
642
643    fn importance(&self) -> DiagImportance {
644        // Most likely the code will try to do mutation with these borrows, which
645        // triggers its own errors. Only show this one if that does not happen.
646        DiagImportance::Secondary
647    }
648
649    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
650        ccx.dcx().create_err(errors::MutableBorrowEscaping { span, kind: ccx.const_kind() })
651    }
652}
653
654/// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
655#[derive(#[automatically_derived]
impl ::core::fmt::Debug for PanicNonStr {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "PanicNonStr")
    }
}Debug)]
656pub(crate) struct PanicNonStr;
657impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
658    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
659        ccx.dcx().create_err(errors::PanicNonStrErr { span })
660    }
661}
662
663/// Comparing raw pointers for equality.
664/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
665/// allocation base addresses that are not known at compile-time.
666#[derive(#[automatically_derived]
impl ::core::fmt::Debug for RawPtrComparison {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "RawPtrComparison")
    }
}Debug)]
667pub(crate) struct RawPtrComparison;
668impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
669    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
670        // FIXME(const_trait_impl): revert to span_bug?
671        ccx.dcx().create_err(errors::RawPtrComparisonErr { span })
672    }
673}
674
675/// Casting raw pointer or function pointer to an integer.
676/// Not currently intended to ever be allowed, even behind a feature gate: operation depends on
677/// allocation base addresses that are not known at compile-time.
678#[derive(#[automatically_derived]
impl ::core::fmt::Debug for RawPtrToIntCast {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "RawPtrToIntCast")
    }
}Debug)]
679pub(crate) struct RawPtrToIntCast;
680impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
681    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
682        ccx.dcx().create_err(errors::RawPtrToIntErr { span })
683    }
684}
685
686/// An access to a thread-local `static`.
687#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ThreadLocalAccess {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "ThreadLocalAccess")
    }
}Debug)]
688pub(crate) struct ThreadLocalAccess;
689impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
690    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
691        ccx.dcx().create_err(errors::ThreadLocalAccessErr { span })
692    }
693}