Skip to main content

rustc_const_eval/const_eval/
eval_queries.rs

1use std::sync::atomic::Ordering::Relaxed;
2
3use either::{Left, Right};
4use rustc_abi::{self as abi, BackendRepr};
5use rustc_hir::def::DefKind;
6use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo};
7use rustc_middle::mir::{self, ConstAlloc, ConstValue};
8use rustc_middle::query::TyCtxtAt;
9use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout};
10use rustc_middle::ty::print::with_no_trimmed_paths;
11use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
12use rustc_middle::{bug, throw_inval};
13use rustc_span::Span;
14use rustc_span::def_id::LocalDefId;
15use tracing::{debug, instrument, trace};
16
17use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine};
18use crate::const_eval::CheckAlignment;
19use crate::interpret::{
20    CtfeValidationMode, GlobalId, Immediate, InternError, InternKind, InterpCx, InterpErrorKind,
21    InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, ReturnContinuation, create_static_alloc,
22    ensure_monomorphic_enough, intern_const_alloc_recursive, interp_ok, throw_exhaust,
23};
24use crate::{CTRL_C_RECEIVED, diagnostics};
25
26fn retry_codegen_mode_with_postanalysis<'tcx, K: TypeVisitable<TyCtxt<'tcx>>, V>(
27    key: ty::PseudoCanonicalInput<'tcx, K>,
28    f: impl FnOnce(ty::PseudoCanonicalInput<'tcx, K>) -> Result<V, ErrorHandled>,
29) -> Option<Result<V, ErrorHandled>> {
30    let ty::PseudoCanonicalInput { typing_env, value } = key;
31    match typing_env.typing_mode().assert_not_erased() {
32        // We are in codegen. It's very likely this constant has been evaluated in PostAnalysis
33        // before. Try to reuse this evaluation, and only re-run if we hit a `TooGeneric` error.
34        ty::TypingMode::Codegen => {
35            let with_postanalysis =
36                ty::TypingEnv::new(typing_env.param_env, ty::TypingMode::PostAnalysis);
37            let with_postanalysis = f(with_postanalysis.as_query_input(value));
38            match with_postanalysis {
39                Ok(_) | Err(ErrorHandled::Reported(..)) => return Some(with_postanalysis),
40                Err(ErrorHandled::TooGeneric(_)) => {}
41            }
42        }
43        ty::TypingMode::Coherence
44        | ty::TypingMode::Typeck { .. }
45        | ty::TypingMode::PostTypeckUntilBorrowck { .. }
46        | ty::TypingMode::PostBorrowck { .. }
47        | ty::TypingMode::Reflection
48        | ty::TypingMode::PostAnalysis => {}
49    }
50
51    None
52}
53
54fn setup_for_eval<'tcx>(
55    ecx: &mut CompileTimeInterpCx<'tcx>,
56    cid: GlobalId<'tcx>,
57    layout: TyAndLayout<'tcx>,
58) -> InterpResult<'tcx, (InternKind, MPlaceTy<'tcx>)> {
59    let tcx = *ecx.tcx;
60    if !(cid.promoted.is_some() ||
            #[allow(non_exhaustive_omitted_patterns)] match ecx.tcx.def_kind(cid.instance.def_id())
                {
                DefKind::Const { .. } | DefKind::Static { .. } |
                    DefKind::ConstParam | DefKind::AnonConst |
                    DefKind::AssocConst { .. } => true,
                _ => false,
            }) {
    {
        ::core::panicking::panic_fmt(format_args!("Unexpected DefKind: {0:?}",
                ecx.tcx.def_kind(cid.instance.def_id())));
    }
};assert!(
61        cid.promoted.is_some()
62            || matches!(
63                ecx.tcx.def_kind(cid.instance.def_id()),
64                DefKind::Const { .. }
65                    | DefKind::Static { .. }
66                    | DefKind::ConstParam
67                    | DefKind::AnonConst
68                    | DefKind::AssocConst { .. }
69            ),
70        "Unexpected DefKind: {:?}",
71        ecx.tcx.def_kind(cid.instance.def_id())
72    );
73    if !layout.is_sized() {
    ::core::panicking::panic("assertion failed: layout.is_sized()")
};assert!(layout.is_sized());
74
75    let intern_kind = if cid.promoted.is_some() {
76        InternKind::Promoted
77    } else {
78        match tcx.static_mutability(cid.instance.def_id()) {
79            Some(m) => InternKind::Static(m),
80            None => InternKind::Constant,
81        }
82    };
83
84    let return_place = if let InternKind::Static(_) = intern_kind {
85        create_static_alloc(ecx, cid.instance.def_id().expect_local(), layout)
86    } else {
87        ecx.allocate(layout, MemoryKind::Stack)
88    };
89
90    return_place.map(|ret| (intern_kind, ret))
91}
92
93#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("eval_body_using_ecx",
                                    "rustc_const_eval::const_eval::eval_queries",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/const_eval/eval_queries.rs"),
                                    ::tracing_core::__macro_support::Option::Some(93u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("cid")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("cid");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&cid)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: InterpResult<'tcx, R> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let tcx = *ecx.tcx;
            let ty =
                body.bound_return_ty(tcx).instantiate(tcx,
                        cid.instance.args).skip_norm_wip();
            ensure_monomorphic_enough(ty)?;
            let layout = ecx.layout_of(ty)?;
            let (intern_kind, ret) = setup_for_eval(ecx, cid, layout)?;
            {
                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/const_eval/eval_queries.rs:106",
                                    "rustc_const_eval::const_eval::eval_queries",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/const_eval/eval_queries.rs"),
                                    ::tracing_core::__macro_support::Option::Some(106u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&["message"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::EVENT)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let enabled =
                    ::tracing::Level::TRACE <=
                                ::tracing::level_filters::STATIC_MAX_LEVEL &&
                            ::tracing::Level::TRACE <=
                                ::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!("eval_body_using_ecx: pushing stack frame for global: {0}{1}",
                                                                {
                                                                    let _guard = NoTrimmedGuard::new();
                                                                    ecx.tcx.def_path_str(cid.instance.def_id())
                                                                },
                                                                cid.promoted.map_or_else(String::new,
                                                                    |p|
                                                                        ::alloc::__export::must_use({
                                                                                ::alloc::fmt::format(format_args!("::{0:?}", p))
                                                                            }))) as &dyn ::tracing::field::Value))])
                        });
                } else { ; }
            };
            ecx.push_stack_frame_raw(cid.instance, body, &ret.clone().into(),
                    ReturnContinuation::Stop { cleanup: false })?;
            ecx.push_stack_frame_done()?;
            while ecx.step()? {
                if CTRL_C_RECEIVED.load(Relaxed) {
                    do yeet ::rustc_middle::mir::interpret::InterpErrorKind::ResourceExhaustion(::rustc_middle::mir::interpret::ResourceExhaustionInfo::Interrupted);
                }
            }
            intern_and_validate(ecx, cid, intern_kind, ret)
        }
    }
}#[instrument(level = "trace", skip(ecx, body))]
94fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
95    ecx: &mut CompileTimeInterpCx<'tcx>,
96    cid: GlobalId<'tcx>,
97    body: &'tcx mir::Body<'tcx>,
98) -> InterpResult<'tcx, R> {
99    let tcx = *ecx.tcx;
100    let ty = body.bound_return_ty(tcx).instantiate(tcx, cid.instance.args).skip_norm_wip();
101    ensure_monomorphic_enough(ty)?;
102
103    let layout = ecx.layout_of(ty)?;
104    let (intern_kind, ret) = setup_for_eval(ecx, cid, layout)?;
105
106    trace!(
107        "eval_body_using_ecx: pushing stack frame for global: {}{}",
108        with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())),
109        cid.promoted.map_or_else(String::new, |p| format!("::{p:?}"))
110    );
111
112    // This can't use `init_stack_frame` since `body` is not a function,
113    // so computing its ABI would fail. It's also not worth it since there are no arguments to pass.
114    ecx.push_stack_frame_raw(
115        cid.instance,
116        body,
117        &ret.clone().into(),
118        ReturnContinuation::Stop { cleanup: false },
119    )?;
120    ecx.push_stack_frame_done()?;
121
122    // The main interpreter loop.
123    while ecx.step()? {
124        if CTRL_C_RECEIVED.load(Relaxed) {
125            throw_exhaust!(Interrupted);
126        }
127    }
128
129    intern_and_validate(ecx, cid, intern_kind, ret)
130}
131
132#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("eval_trivial_const_using_ecx",
                                    "rustc_const_eval::const_eval::eval_queries",
                                    ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/const_eval/eval_queries.rs"),
                                    ::tracing_core::__macro_support::Option::Some(132u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("cid")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("cid");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("val")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("val");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("ty")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("ty");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&cid)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&val)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: InterpResult<'tcx, R> = loop {};
            return __tracing_attr_fake_return;
        }
        {
            let layout = ecx.layout_of(ty)?;
            let (intern_kind, return_place) =
                setup_for_eval(ecx, cid, layout)?;
            let opty = ecx.const_val_to_op(val, ty, Some(layout))?;
            ecx.copy_op(&opty, &return_place)?;
            intern_and_validate(ecx, cid, intern_kind, return_place)
        }
    }
}#[instrument(level = "trace", skip(ecx))]
133fn eval_trivial_const_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
134    ecx: &mut CompileTimeInterpCx<'tcx>,
135    cid: GlobalId<'tcx>,
136    val: ConstValue,
137    ty: Ty<'tcx>,
138) -> InterpResult<'tcx, R> {
139    let layout = ecx.layout_of(ty)?;
140    let (intern_kind, return_place) = setup_for_eval(ecx, cid, layout)?;
141
142    let opty = ecx.const_val_to_op(val, ty, Some(layout))?;
143    ecx.copy_op(&opty, &return_place)?;
144
145    intern_and_validate(ecx, cid, intern_kind, return_place)
146}
147
148fn intern_and_validate<'tcx, R: InterpretationResult<'tcx>>(
149    ecx: &mut CompileTimeInterpCx<'tcx>,
150    cid: GlobalId<'tcx>,
151    intern_kind: InternKind,
152    ret: MPlaceTy<'tcx>,
153) -> InterpResult<'tcx, R> {
154    // Intern the result
155    let intern_result = intern_const_alloc_recursive(ecx, intern_kind, &ret);
156
157    // Since evaluation had no errors, validate the resulting constant.
158    const_validate_mplace(ecx, &ret, cid)?;
159
160    // Only report this after validation, as validation produces much better diagnostics.
161    // FIXME: ensure validation always reports this and stop making interning care about it.
162
163    match intern_result {
164        Ok(()) => {}
165        Err(InternError::DanglingPointer) => {
166            do yeet ::rustc_middle::mir::interpret::InterpErrorKind::InvalidProgram(::rustc_middle::mir::interpret::InvalidProgramInfo::AlreadyReported(ReportedErrorInfo::non_const_eval_error(ecx.tcx.dcx().emit_err(diagnostics::DanglingPtrInFinal {
                        span: ecx.tcx.span,
                        kind: intern_kind,
                    }))));throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(
167                ecx.tcx.dcx().emit_err(diagnostics::DanglingPtrInFinal {
168                    span: ecx.tcx.span,
169                    kind: intern_kind
170                }),
171            )));
172        }
173        Err(InternError::BadMutablePointer) => {
174            do yeet ::rustc_middle::mir::interpret::InterpErrorKind::InvalidProgram(::rustc_middle::mir::interpret::InvalidProgramInfo::AlreadyReported(ReportedErrorInfo::non_const_eval_error(ecx.tcx.dcx().emit_err(diagnostics::MutablePtrInFinal {
                        span: ecx.tcx.span,
                        kind: intern_kind,
                    }))));throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(
175                ecx.tcx.dcx().emit_err(diagnostics::MutablePtrInFinal {
176                    span: ecx.tcx.span,
177                    kind: intern_kind
178                }),
179            )));
180        }
181        Err(InternError::ConstAllocNotGlobal) => {
182            do yeet ::rustc_middle::mir::interpret::InterpErrorKind::InvalidProgram(::rustc_middle::mir::interpret::InvalidProgramInfo::AlreadyReported(ReportedErrorInfo::non_const_eval_error(ecx.tcx.dcx().emit_err(diagnostics::ConstHeapPtrInFinal {
                        span: ecx.tcx.span,
                    }))));throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(
183                ecx.tcx.dcx().emit_err(diagnostics::ConstHeapPtrInFinal { span: ecx.tcx.span }),
184            )));
185        }
186        Err(InternError::PartialPointer) => {
187            do yeet ::rustc_middle::mir::interpret::InterpErrorKind::InvalidProgram(::rustc_middle::mir::interpret::InvalidProgramInfo::AlreadyReported(ReportedErrorInfo::non_const_eval_error(ecx.tcx.dcx().emit_err(diagnostics::PartialPtrInFinal {
                        span: ecx.tcx.span,
                        kind: intern_kind,
                    }))));throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(
188                ecx.tcx.dcx().emit_err(diagnostics::PartialPtrInFinal {
189                    span: ecx.tcx.span,
190                    kind: intern_kind
191                }),
192            )));
193        }
194    }
195
196    interp_ok(R::make_result(ret, ecx))
197}
198
199/// The `InterpCx` is only meant to be used to do field and index projections into constants for
200/// `simd_shuffle` and const patterns in match arms.
201///
202/// This should *not* be used to do any actual interpretation. In particular, alignment checks are
203/// turned off!
204///
205/// The function containing the `match` that is currently being analyzed may have generic bounds
206/// that inform us about the generic bounds of the constant. E.g., using an associated constant
207/// of a function's generic parameter will require knowledge about the bounds on the generic
208/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
209pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>(
210    tcx: TyCtxt<'tcx>,
211    root_span: Span,
212    typing_env: ty::TypingEnv<'tcx>,
213    can_access_mut_global: CanAccessMutGlobal,
214) -> CompileTimeInterpCx<'tcx> {
215    {
    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/const_eval/eval_queries.rs:215",
                        "rustc_const_eval::const_eval::eval_queries",
                        ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/const_eval/eval_queries.rs"),
                        ::tracing_core::__macro_support::Option::Some(215u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                        ::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!("mk_eval_cx: {0:?}",
                                                    typing_env) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};debug!("mk_eval_cx: {:?}", typing_env);
216    InterpCx::new(
217        tcx,
218        root_span,
219        typing_env,
220        CompileTimeMachine::new(can_access_mut_global, CheckAlignment::No),
221    )
222}
223
224/// Create an interpreter context to inspect the given `ConstValue`.
225/// Returns both the context and an `OpTy` that represents the constant.
226pub fn mk_eval_cx_for_const_val<'tcx>(
227    tcx: TyCtxtAt<'tcx>,
228    typing_env: ty::TypingEnv<'tcx>,
229    val: mir::ConstValue,
230    ty: Ty<'tcx>,
231) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> {
232    let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, typing_env, CanAccessMutGlobal::No);
233    // FIXME: is it a problem to discard the error here?
234    let op = ecx.const_val_to_op(val, ty, None).discard_err()?;
235    Some((ecx, op))
236}
237
238/// This function converts an interpreter value into a MIR constant.
239///
240/// The `for_diagnostics` flag turns the usual rules for returning `ConstValue::Scalar` into a
241/// best-effort attempt. This is not okay for use in const-eval sine it breaks invariants rustc
242/// relies on, but it is okay for diagnostics which will just give up gracefully when they
243/// encounter an `Indirect` they cannot handle.
244#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("op_to_const",
                                    "rustc_const_eval::const_eval::eval_queries",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/const_eval/eval_queries.rs"),
                                    ::tracing_core::__macro_support::Option::Some(244u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("op")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("op");
                                                        NAME.as_str()
                                                    },
                                                    {
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("for_diagnostics")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("for_diagnostics");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&op)
                                                            as &dyn ::tracing::field::Value)),
                                                (::tracing::__macro_support::Option::Some(&for_diagnostics
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: ConstValue = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if op.layout.is_zst() { return ConstValue::ZeroSized; }
            let force_as_immediate =
                match op.layout.backend_repr {
                    BackendRepr::Scalar(abi::Scalar::Initialized { .. }) =>
                        true,
                    _ => false,
                };
            let immediate =
                if force_as_immediate {
                    match ecx.read_immediate(op).report_err() {
                        Ok(imm) => Right(imm),
                        Err(err) => {
                            if for_diagnostics {
                                op.as_mplace_or_imm()
                            } else {
                                {
                                    ::core::panicking::panic_fmt(format_args!("normalization works on validated constants: {0:?}",
                                            err));
                                }
                            }
                        }
                    }
                } else { op.as_mplace_or_imm() };
            {
                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/const_eval/eval_queries.rs:287",
                                    "rustc_const_eval::const_eval::eval_queries",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/const_eval/eval_queries.rs"),
                                    ::tracing_core::__macro_support::Option::Some(287u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("immediate")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("immediate");
                                                        NAME.as_str()
                                                    }], ::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(&::tracing::field::debug(&immediate)
                                                        as &dyn ::tracing::field::Value))])
                        });
                } else { ; }
            };
            match immediate {
                Left(ref mplace) => {
                    let (prov, offset) =
                        mplace.ptr().into_pointer_or_addr().unwrap().prov_and_relative_offset();
                    let alloc_id = prov.alloc_id();
                    ConstValue::Indirect { alloc_id, offset }
                }
                Right(imm) =>
                    match *imm {
                        Immediate::Scalar(x) => ConstValue::Scalar(x),
                        Immediate::ScalarPair(a, b) => {
                            {
                                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/const_eval/eval_queries.rs:300",
                                                    "rustc_const_eval::const_eval::eval_queries",
                                                    ::tracing::Level::DEBUG,
                                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/const_eval/eval_queries.rs"),
                                                    ::tracing_core::__macro_support::Option::Some(300u32),
                                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                                    ::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!("ScalarPair(a: {0:?}, b: {1:?})",
                                                                                a, b) as &dyn ::tracing::field::Value))])
                                        });
                                } else { ; }
                            };
                            let pointee_ty =
                                imm.layout.ty.builtin_deref(false).unwrap();
                            if true {
                                if !#[allow(non_exhaustive_omitted_patterns)] match ecx.tcx.struct_tail_for_codegen(pointee_ty,
                                                    ecx.typing_env()).kind() {
                                            ty::Str | ty::Slice(..) => true,
                                            _ => false,
                                        } {
                                    {
                                        ::core::panicking::panic_fmt(format_args!("`ConstValue::Slice` is for slice-tailed types only, but got {0}",
                                                imm.layout.ty));
                                    }
                                };
                            };
                            let msg =
                                "`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation";
                            let ptr = a.to_pointer(ecx).expect(msg);
                            let (prov, offset) =
                                ptr.into_pointer_or_addr().expect(msg).prov_and_relative_offset();
                            let alloc_id = prov.alloc_id();
                            if !(offset == abi::Size::ZERO) {
                                { ::core::panicking::panic_display(&msg); }
                            };
                            let meta = b.to_target_usize(ecx).expect(msg);
                            ConstValue::Slice { alloc_id, meta }
                        }
                        Immediate::Uninit =>
                            ::rustc_middle::util::bug::bug_fmt(format_args!("`Uninit` is not a valid value for {0}",
                                    op.layout.ty)),
                    },
            }
        }
    }
}#[instrument(skip(ecx), level = "debug")]
245pub(super) fn op_to_const<'tcx>(
246    ecx: &CompileTimeInterpCx<'tcx>,
247    op: &OpTy<'tcx>,
248    for_diagnostics: bool,
249) -> ConstValue {
250    // Handle ZST consistently and early.
251    if op.layout.is_zst() {
252        return ConstValue::ZeroSized;
253    }
254
255    // All scalar types should be stored as `ConstValue::Scalar`. This is needed to make
256    // `ConstValue::try_to_scalar` efficient; we want that to work for *all* constants of scalar
257    // type (it's used throughout the compiler and having it work just on literals is not enough)
258    // and we want it to be fast (i.e., don't go to an `Allocation` and reconstruct the `Scalar`
259    // from its byte-serialized form).
260    let force_as_immediate = match op.layout.backend_repr {
261        BackendRepr::Scalar(abi::Scalar::Initialized { .. }) => true,
262        // We don't *force* `ConstValue::Slice` for `ScalarPair`. This has the advantage that if the
263        // input `op` is a place, then turning it into a `ConstValue` and back into a `OpTy` will
264        // not have to generate any duplicate allocations (we preserve the original `AllocId` in
265        // `ConstValue::Indirect`). It means accessing the contents of a slice can be slow (since
266        // they can be stored as `ConstValue::Indirect`), but that's not relevant since we barely
267        // ever have to do this. (`try_get_slice_bytes_for_diagnostics` exists to provide this
268        // functionality.)
269        _ => false,
270    };
271    let immediate = if force_as_immediate {
272        match ecx.read_immediate(op).report_err() {
273            Ok(imm) => Right(imm),
274            Err(err) => {
275                if for_diagnostics {
276                    // This discard the error, but for diagnostics that's okay.
277                    op.as_mplace_or_imm()
278                } else {
279                    panic!("normalization works on validated constants: {err:?}")
280                }
281            }
282        }
283    } else {
284        op.as_mplace_or_imm()
285    };
286
287    debug!(?immediate);
288
289    match immediate {
290        Left(ref mplace) => {
291            let (prov, offset) =
292                mplace.ptr().into_pointer_or_addr().unwrap().prov_and_relative_offset();
293            let alloc_id = prov.alloc_id();
294            ConstValue::Indirect { alloc_id, offset }
295        }
296        // see comment on `let force_as_immediate` above
297        Right(imm) => match *imm {
298            Immediate::Scalar(x) => ConstValue::Scalar(x),
299            Immediate::ScalarPair(a, b) => {
300                debug!("ScalarPair(a: {:?}, b: {:?})", a, b);
301                // This codepath solely exists for `valtree_to_const_value` to not need to generate
302                // a `ConstValue::Indirect` for wide references, so it is tightly restricted to just
303                // that case.
304                let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs
305                debug_assert!(
306                    matches!(
307                        ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(),
308                        ty::Str | ty::Slice(..),
309                    ),
310                    "`ConstValue::Slice` is for slice-tailed types only, but got {}",
311                    imm.layout.ty,
312                );
313                let msg = "`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation";
314                let ptr = a.to_pointer(ecx).expect(msg);
315                let (prov, offset) =
316                    ptr.into_pointer_or_addr().expect(msg).prov_and_relative_offset();
317                let alloc_id = prov.alloc_id();
318                assert!(offset == abi::Size::ZERO, "{}", msg);
319                let meta = b.to_target_usize(ecx).expect(msg);
320                ConstValue::Slice { alloc_id, meta }
321            }
322            Immediate::Uninit => bug!("`Uninit` is not a valid value for {}", op.layout.ty),
323        },
324    }
325}
326
327x;#[instrument(skip(tcx), level = "debug", ret)]
328pub(crate) fn turn_into_const_value<'tcx>(
329    tcx: TyCtxt<'tcx>,
330    constant: ConstAlloc<'tcx>,
331    key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
332) -> ConstValue {
333    let cid = key.value;
334    let def_id = cid.instance.def.def_id();
335    let is_static = tcx.is_static(def_id);
336    // This is just accessing an already computed constant, so no need to check alignment here.
337    let ecx = mk_eval_cx_to_read_const_val(
338        tcx,
339        tcx.def_span(key.value.instance.def_id()),
340        key.typing_env,
341        CanAccessMutGlobal::from(is_static),
342    );
343
344    let mplace = ecx.raw_const_to_mplace(constant).expect(
345        "can only fail if layout computation failed, \
346        which should have given a good error before ever invoking this function",
347    );
348    assert!(
349        !is_static || cid.promoted.is_some(),
350        "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead"
351    );
352
353    // Turn this into a proper constant.
354    op_to_const(&ecx, &mplace.into(), /* for diagnostics */ false)
355}
356
357#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("eval_to_const_value_raw_provider",
                                    "rustc_const_eval::const_eval::eval_queries",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/const_eval/eval_queries.rs"),
                                    ::tracing_core::__macro_support::Option::Some(357u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("key")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("key");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&key)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return:
                    ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            crate::assert_typing_mode(key.typing_env.typing_mode());
            if let Some((value, _ty)) =
                    tcx.trivial_const(key.value.instance.def_id()) {
                return Ok(value);
            }
            if let Some(retry) =
                    retry_codegen_mode_with_postanalysis(key,
                        |key| tcx.eval_to_const_value_raw(key)) {
                return retry;
            }
            tcx.eval_to_allocation_raw(key).map(|val|
                    turn_into_const_value(tcx, val, key))
        }
    }
}#[instrument(skip(tcx), level = "debug")]
358pub fn eval_to_const_value_raw_provider<'tcx>(
359    tcx: TyCtxt<'tcx>,
360    key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
361) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
362    crate::assert_typing_mode(key.typing_env.typing_mode());
363
364    if let Some((value, _ty)) = tcx.trivial_const(key.value.instance.def_id()) {
365        return Ok(value);
366    }
367
368    if let Some(retry) =
369        retry_codegen_mode_with_postanalysis(key, |key| tcx.eval_to_const_value_raw(key))
370    {
371        return retry;
372    }
373
374    tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
375}
376
377#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("eval_static_initializer_provider",
                                    "rustc_const_eval::const_eval::eval_queries",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/const_eval/eval_queries.rs"),
                                    ::tracing_core::__macro_support::Option::Some(377u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("def_id")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("def_id");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&def_id)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return:
                    ::rustc_middle::mir::interpret::EvalStaticInitializerRawResult<'tcx> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            if !tcx.is_static(def_id.to_def_id()) {
                ::core::panicking::panic("assertion failed: tcx.is_static(def_id.to_def_id())")
            };
            let instance = ty::Instance::mono(tcx, def_id.to_def_id());
            let cid =
                rustc_middle::mir::interpret::GlobalId {
                    instance,
                    promoted: None,
                };
            eval_in_interpreter(tcx, cid,
                ty::TypingEnv::fully_monomorphized())
        }
    }
}#[instrument(skip(tcx), level = "debug")]
378pub fn eval_static_initializer_provider<'tcx>(
379    tcx: TyCtxt<'tcx>,
380    def_id: LocalDefId,
381) -> ::rustc_middle::mir::interpret::EvalStaticInitializerRawResult<'tcx> {
382    assert!(tcx.is_static(def_id.to_def_id()));
383
384    let instance = ty::Instance::mono(tcx, def_id.to_def_id());
385    let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None };
386    eval_in_interpreter(tcx, cid, ty::TypingEnv::fully_monomorphized())
387}
388
389pub trait InterpretationResult<'tcx> {
390    /// This function takes the place where the result of the evaluation is stored
391    /// and prepares it for returning it in the appropriate format needed by the specific
392    /// evaluation query.
393    fn make_result(
394        mplace: MPlaceTy<'tcx>,
395        ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>,
396    ) -> Self;
397}
398
399impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> {
400    fn make_result(
401        mplace: MPlaceTy<'tcx>,
402        _ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>,
403    ) -> Self {
404        ConstAlloc { alloc_id: mplace.ptr().provenance.unwrap().alloc_id(), ty: mplace.layout.ty }
405    }
406}
407
408#[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("eval_to_allocation_raw_provider",
                                    "rustc_const_eval::const_eval::eval_queries",
                                    ::tracing::Level::DEBUG,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/const_eval/eval_queries.rs"),
                                    ::tracing_core::__macro_support::Option::Some(408u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&[{
                                                        const NAME:
                                                            ::tracing::__macro_support::FieldName<{
                                                                ::tracing::__macro_support::FieldName::len("key")
                                                            }> =
                                                            ::tracing::__macro_support::FieldName::new("key");
                                                        NAME.as_str()
                                                    }], ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::DEBUG <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&key)
                                                            as &dyn ::tracing::field::Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return:
                    ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> =
                loop {};
            return __tracing_attr_fake_return;
        }
        {
            crate::assert_typing_mode(key.typing_env.typing_mode());
            if let Some(retry) =
                    retry_codegen_mode_with_postanalysis(key,
                        |key| tcx.eval_to_allocation_raw(key)) {
                return retry;
            }
            if !(key.value.promoted.is_some() ||
                        !tcx.is_static(key.value.instance.def_id())) {
                ::core::panicking::panic("assertion failed: key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id())")
            };
            if true {
                let instance =
                    {
                        let _guard = NoTrimmedGuard::new();
                        key.value.instance.to_string()
                    };
                {
                    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/const_eval/eval_queries.rs:431",
                                        "rustc_const_eval::const_eval::eval_queries",
                                        ::tracing::Level::TRACE,
                                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/const_eval/eval_queries.rs"),
                                        ::tracing_core::__macro_support::Option::Some(431u32),
                                        ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                        ::tracing_core::field::FieldSet::new(&["message"],
                                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                        ::tracing::metadata::Kind::EVENT)
                                };
                            ::tracing::callsite::DefaultCallsite::new(&META)
                        };
                    let enabled =
                        ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::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!("const eval: {0:?} ({1})",
                                                                    key, instance) as &dyn ::tracing::field::Value))])
                            });
                    } else { ; }
                };
            }
            eval_in_interpreter(tcx, key.value, key.typing_env)
        }
    }
}#[instrument(skip(tcx), level = "debug")]
409pub fn eval_to_allocation_raw_provider<'tcx>(
410    tcx: TyCtxt<'tcx>,
411    key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
412) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
413    crate::assert_typing_mode(key.typing_env.typing_mode());
414    if let Some(retry) =
415        retry_codegen_mode_with_postanalysis(key, |key| tcx.eval_to_allocation_raw(key))
416    {
417        return retry;
418    }
419
420    // This shouldn't be used for statics, since statics are conceptually places,
421    // not values -- so what we do here could break pointer identity.
422    assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));
423
424    if cfg!(debug_assertions) {
425        // Make sure we format the instance even if we do not print it.
426        // This serves as a regression test against an ICE on printing.
427        // The next two lines concatenated contain some discussion:
428        // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/
429        // subject/anon_const_instance_printing/near/135980032
430        let instance = with_no_trimmed_paths!(key.value.instance.to_string());
431        trace!("const eval: {:?} ({})", key, instance);
432    }
433
434    eval_in_interpreter(tcx, key.value, key.typing_env)
435}
436
437fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
438    tcx: TyCtxt<'tcx>,
439    cid: GlobalId<'tcx>,
440    typing_env: ty::TypingEnv<'tcx>,
441) -> Result<R, ErrorHandled> {
442    let def = cid.instance.def.def_id();
443    // `type const` don't have bodys
444    if true {
    if !!tcx.is_type_const(def) {
        {
            ::core::panicking::panic_fmt(format_args!("CTFE tried to evaluate type-const: {0:?}",
                    def));
        }
    };
};debug_assert!(!tcx.is_type_const(def), "CTFE tried to evaluate type-const: {:?}", def);
445
446    let is_static = tcx.is_static(def);
447    let mut ecx = InterpCx::new(
448        tcx,
449        tcx.def_span(def),
450        typing_env,
451        // Statics (and promoteds inside statics) may access mutable global memory, because unlike consts
452        // they do not have to behave "as if" they were evaluated at runtime.
453        // For consts however we want to ensure they behave "as if" they were evaluated at runtime,
454        // so we have to reject reading mutable global memory.
455        CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error),
456    );
457
458    let result = if let Some((value, ty)) = tcx.trivial_const(def) {
459        eval_trivial_const_using_ecx(&mut ecx, cid, value, ty)
460    } else {
461        ecx.load_mir(cid.instance.def, cid.promoted)
462            .and_then(|body| eval_body_using_ecx(&mut ecx, cid, body))
463    };
464    result.report_err().map_err(|error| report_eval_error(&ecx, cid, error))
465}
466
467#[inline(always)]
468fn const_validate_mplace<'tcx>(
469    ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>,
470    mplace: &MPlaceTy<'tcx>,
471    cid: GlobalId<'tcx>,
472) -> Result<(), ErrorHandled> {
473    let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
474    let mut ref_tracking = RefTracking::new(mplace.clone(), mplace.layout.ty);
475    let mut inner = false;
476    while let Some((mplace, path)) = ref_tracking.next() {
477        let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {
478            _ if cid.promoted.is_some() => CtfeValidationMode::Promoted,
479            Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
480            None => {
481                // This is a normal `const` (not promoted).
482                // The outermost allocation is always only copied, so having `UnsafeCell` in there
483                // is okay despite them being in immutable memory.
484                CtfeValidationMode::Const { allow_immutable_unsafe_cell: !inner }
485            }
486        };
487        ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)
488            .report_err()
489            // Instead of just reporting the `InterpError` via the usual machinery, we give a more targeted
490            // error about the validation failure.
491            .map_err(|error| report_validation_error(&ecx, cid, error, alloc_id))?;
492        inner = true;
493    }
494
495    Ok(())
496}
497
498#[inline(never)]
499fn report_eval_error<'tcx>(
500    ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>,
501    cid: GlobalId<'tcx>,
502    error: InterpErrorInfo<'tcx>,
503) -> ErrorHandled {
504    let (error, backtrace) = error.into_parts();
505    backtrace.print_backtrace();
506
507    super::report(ecx, error, |diag, span, frames| {
508        let num_frames = frames.len();
509        diag.span_label(
510            span,
511            ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("evaluation of `{0}` failed {1}",
                {
                    let _guard = NoTrimmedGuard::new();
                    cid.instance.to_string()
                }, if num_frames == 0 { "here" } else { "inside this call" }))
    })format!(
512                "evaluation of `{instance}` failed {where_}",
513                instance = with_no_trimmed_paths!(cid.instance.to_string()),
514                where_ = if num_frames == 0 { "here" } else { "inside this call" },
515            ),
516        );
517        for frame in frames {
518            diag.subdiagnostic(frame);
519        }
520    })
521}
522
523#[inline(never)]
524fn report_validation_error<'tcx>(
525    ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>,
526    cid: GlobalId<'tcx>,
527    error: InterpErrorInfo<'tcx>,
528    alloc_id: AllocId,
529) -> ErrorHandled {
530    if !#[allow(non_exhaustive_omitted_patterns)] match error.kind() {
    InterpErrorKind::UndefinedBehavior(_) => true,
    _ => false,
}matches!(error.kind(), InterpErrorKind::UndefinedBehavior(_)) {
531        // Some other error happened during validation, e.g. an unsupported operation.
532        return report_eval_error(ecx, cid, error);
533    }
534
535    let (error, backtrace) = error.into_parts();
536    backtrace.print_backtrace();
537
538    let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id);
539    let info = ecx.get_alloc_info(alloc_id);
540    let raw_bytes =
541        diagnostics::RawBytesNote { size: info.size.bytes(), align: info.align.bytes(), bytes };
542
543    crate::const_eval::report(ecx, error, move |diag, span, frames| {
544        diag.span_label(span, "it is undefined behavior to use this value");
545        diag.note("the rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.");
546        if !frames.is_empty() {
    ::core::panicking::panic("assertion failed: frames.is_empty()")
};assert!(frames.is_empty()); // we just report validation errors for the final const here
547        diag.subdiagnostic(raw_bytes);
548    })
549}