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    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::PostAnalysis => {}
48    }
49
50    None
51}
52
53fn setup_for_eval<'tcx>(
54    ecx: &mut CompileTimeInterpCx<'tcx>,
55    cid: GlobalId<'tcx>,
56    layout: TyAndLayout<'tcx>,
57) -> InterpResult<'tcx, (InternKind, MPlaceTy<'tcx>)> {
58    let tcx = *ecx.tcx;
59    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!(
60        cid.promoted.is_some()
61            || matches!(
62                ecx.tcx.def_kind(cid.instance.def_id()),
63                DefKind::Const { .. }
64                    | DefKind::Static { .. }
65                    | DefKind::ConstParam
66                    | DefKind::AnonConst
67                    | DefKind::AssocConst { .. }
68            ),
69        "Unexpected DefKind: {:?}",
70        ecx.tcx.def_kind(cid.instance.def_id())
71    );
72    if !layout.is_sized() {
    ::core::panicking::panic("assertion failed: layout.is_sized()")
};assert!(layout.is_sized());
73
74    let intern_kind = if cid.promoted.is_some() {
75        InternKind::Promoted
76    } else {
77        match tcx.static_mutability(cid.instance.def_id()) {
78            Some(m) => InternKind::Static(m),
79            None => InternKind::Constant,
80        }
81    };
82
83    let return_place = if let InternKind::Static(_) = intern_kind {
84        create_static_alloc(ecx, cid.instance.def_id().expect_local(), layout)
85    } else {
86        ecx.allocate(layout, MemoryKind::Stack)
87    };
88
89    return_place.map(|ret| (intern_kind, ret))
90}
91
92#[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(92u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&["cid"],
                                        ::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};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&cid)
                                                            as &dyn 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 layout =
                ecx.layout_of(body.bound_return_ty(tcx).instantiate(tcx,
                                cid.instance.args).skip_norm_wip())?;
            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:103",
                                    "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(103u32),
                                    ::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};
                            let mut iter = __CALLSITE.metadata().fields().iter();
                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                ::tracing::__macro_support::Option::Some(&format_args!("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 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))]
93fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
94    ecx: &mut CompileTimeInterpCx<'tcx>,
95    cid: GlobalId<'tcx>,
96    body: &'tcx mir::Body<'tcx>,
97) -> InterpResult<'tcx, R> {
98    let tcx = *ecx.tcx;
99    let layout = ecx
100        .layout_of(body.bound_return_ty(tcx).instantiate(tcx, cid.instance.args).skip_norm_wip())?;
101    let (intern_kind, ret) = setup_for_eval(ecx, cid, layout)?;
102
103    trace!(
104        "eval_body_using_ecx: pushing stack frame for global: {}{}",
105        with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())),
106        cid.promoted.map_or_else(String::new, |p| format!("::{p:?}"))
107    );
108
109    // This can't use `init_stack_frame` since `body` is not a function,
110    // so computing its ABI would fail. It's also not worth it since there are no arguments to pass.
111    ecx.push_stack_frame_raw(
112        cid.instance,
113        body,
114        &ret.clone().into(),
115        ReturnContinuation::Stop { cleanup: false },
116    )?;
117    ecx.push_stack_frame_done()?;
118
119    // The main interpreter loop.
120    while ecx.step()? {
121        if CTRL_C_RECEIVED.load(Relaxed) {
122            throw_exhaust!(Interrupted);
123        }
124    }
125
126    intern_and_validate(ecx, cid, intern_kind, ret)
127}
128
129#[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(129u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&["cid", "val", "ty"],
                                        ::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};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&cid)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&val)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
                                                            as &dyn 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))]
130fn eval_trivial_const_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
131    ecx: &mut CompileTimeInterpCx<'tcx>,
132    cid: GlobalId<'tcx>,
133    val: ConstValue,
134    ty: Ty<'tcx>,
135) -> InterpResult<'tcx, R> {
136    let layout = ecx.layout_of(ty)?;
137    let (intern_kind, return_place) = setup_for_eval(ecx, cid, layout)?;
138
139    let opty = ecx.const_val_to_op(val, ty, Some(layout))?;
140    ecx.copy_op(&opty, &return_place)?;
141
142    intern_and_validate(ecx, cid, intern_kind, return_place)
143}
144
145fn intern_and_validate<'tcx, R: InterpretationResult<'tcx>>(
146    ecx: &mut CompileTimeInterpCx<'tcx>,
147    cid: GlobalId<'tcx>,
148    intern_kind: InternKind,
149    ret: MPlaceTy<'tcx>,
150) -> InterpResult<'tcx, R> {
151    // Intern the result
152    let intern_result = intern_const_alloc_recursive(ecx, intern_kind, &ret);
153
154    // Since evaluation had no errors, validate the resulting constant.
155    const_validate_mplace(ecx, &ret, cid)?;
156
157    // Only report this after validation, as validation produces much better diagnostics.
158    // FIXME: ensure validation always reports this and stop making interning care about it.
159
160    match intern_result {
161        Ok(()) => {}
162        Err(InternError::DanglingPointer) => {
163            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(
164                ecx.tcx.dcx().emit_err(diagnostics::DanglingPtrInFinal {
165                    span: ecx.tcx.span,
166                    kind: intern_kind
167                }),
168            )));
169        }
170        Err(InternError::BadMutablePointer) => {
171            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(
172                ecx.tcx.dcx().emit_err(diagnostics::MutablePtrInFinal {
173                    span: ecx.tcx.span,
174                    kind: intern_kind
175                }),
176            )));
177        }
178        Err(InternError::ConstAllocNotGlobal) => {
179            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(
180                ecx.tcx.dcx().emit_err(diagnostics::ConstHeapPtrInFinal { span: ecx.tcx.span }),
181            )));
182        }
183        Err(InternError::PartialPointer) => {
184            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(
185                ecx.tcx.dcx().emit_err(diagnostics::PartialPtrInFinal {
186                    span: ecx.tcx.span,
187                    kind: intern_kind
188                }),
189            )));
190        }
191    }
192
193    interp_ok(R::make_result(ret, ecx))
194}
195
196/// The `InterpCx` is only meant to be used to do field and index projections into constants for
197/// `simd_shuffle` and const patterns in match arms.
198///
199/// This should *not* be used to do any actual interpretation. In particular, alignment checks are
200/// turned off!
201///
202/// The function containing the `match` that is currently being analyzed may have generic bounds
203/// that inform us about the generic bounds of the constant. E.g., using an associated constant
204/// of a function's generic parameter will require knowledge about the bounds on the generic
205/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
206pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>(
207    tcx: TyCtxt<'tcx>,
208    root_span: Span,
209    typing_env: ty::TypingEnv<'tcx>,
210    can_access_mut_global: CanAccessMutGlobal,
211) -> CompileTimeInterpCx<'tcx> {
212    {
    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:212",
                        "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(212u32),
                        ::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};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("mk_eval_cx: {0:?}",
                                                    typing_env) as &dyn Value))])
            });
    } else { ; }
};debug!("mk_eval_cx: {:?}", typing_env);
213    InterpCx::new(
214        tcx,
215        root_span,
216        typing_env,
217        CompileTimeMachine::new(can_access_mut_global, CheckAlignment::No),
218    )
219}
220
221/// Create an interpreter context to inspect the given `ConstValue`.
222/// Returns both the context and an `OpTy` that represents the constant.
223pub fn mk_eval_cx_for_const_val<'tcx>(
224    tcx: TyCtxtAt<'tcx>,
225    typing_env: ty::TypingEnv<'tcx>,
226    val: mir::ConstValue,
227    ty: Ty<'tcx>,
228) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> {
229    let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, typing_env, CanAccessMutGlobal::No);
230    // FIXME: is it a problem to discard the error here?
231    let op = ecx.const_val_to_op(val, ty, None).discard_err()?;
232    Some((ecx, op))
233}
234
235/// This function converts an interpreter value into a MIR constant.
236///
237/// The `for_diagnostics` flag turns the usual rules for returning `ConstValue::Scalar` into a
238/// best-effort attempt. This is not okay for use in const-eval sine it breaks invariants rustc
239/// relies on, but it is okay for diagnostics which will just give up gracefully when they
240/// encounter an `Indirect` they cannot handle.
241#[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(241u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&["op",
                                                    "for_diagnostics"],
                                        ::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};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&op)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&for_diagnostics as
                                                            &dyn 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:284",
                                    "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(284u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&["immediate"],
                                        ::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(&immediate)
                                                        as &dyn 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:297",
                                                    "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(297u32),
                                                    ::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};
                                            let mut iter = __CALLSITE.metadata().fields().iter();
                                            __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                                ::tracing::__macro_support::Option::Some(&format_args!("ScalarPair(a: {0:?}, b: {1:?})",
                                                                                a, b) as &dyn 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")]
242pub(super) fn op_to_const<'tcx>(
243    ecx: &CompileTimeInterpCx<'tcx>,
244    op: &OpTy<'tcx>,
245    for_diagnostics: bool,
246) -> ConstValue {
247    // Handle ZST consistently and early.
248    if op.layout.is_zst() {
249        return ConstValue::ZeroSized;
250    }
251
252    // All scalar types should be stored as `ConstValue::Scalar`. This is needed to make
253    // `ConstValue::try_to_scalar` efficient; we want that to work for *all* constants of scalar
254    // type (it's used throughout the compiler and having it work just on literals is not enough)
255    // and we want it to be fast (i.e., don't go to an `Allocation` and reconstruct the `Scalar`
256    // from its byte-serialized form).
257    let force_as_immediate = match op.layout.backend_repr {
258        BackendRepr::Scalar(abi::Scalar::Initialized { .. }) => true,
259        // We don't *force* `ConstValue::Slice` for `ScalarPair`. This has the advantage that if the
260        // input `op` is a place, then turning it into a `ConstValue` and back into a `OpTy` will
261        // not have to generate any duplicate allocations (we preserve the original `AllocId` in
262        // `ConstValue::Indirect`). It means accessing the contents of a slice can be slow (since
263        // they can be stored as `ConstValue::Indirect`), but that's not relevant since we barely
264        // ever have to do this. (`try_get_slice_bytes_for_diagnostics` exists to provide this
265        // functionality.)
266        _ => false,
267    };
268    let immediate = if force_as_immediate {
269        match ecx.read_immediate(op).report_err() {
270            Ok(imm) => Right(imm),
271            Err(err) => {
272                if for_diagnostics {
273                    // This discard the error, but for diagnostics that's okay.
274                    op.as_mplace_or_imm()
275                } else {
276                    panic!("normalization works on validated constants: {err:?}")
277                }
278            }
279        }
280    } else {
281        op.as_mplace_or_imm()
282    };
283
284    debug!(?immediate);
285
286    match immediate {
287        Left(ref mplace) => {
288            let (prov, offset) =
289                mplace.ptr().into_pointer_or_addr().unwrap().prov_and_relative_offset();
290            let alloc_id = prov.alloc_id();
291            ConstValue::Indirect { alloc_id, offset }
292        }
293        // see comment on `let force_as_immediate` above
294        Right(imm) => match *imm {
295            Immediate::Scalar(x) => ConstValue::Scalar(x),
296            Immediate::ScalarPair(a, b) => {
297                debug!("ScalarPair(a: {:?}, b: {:?})", a, b);
298                // This codepath solely exists for `valtree_to_const_value` to not need to generate
299                // a `ConstValue::Indirect` for wide references, so it is tightly restricted to just
300                // that case.
301                let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs
302                debug_assert!(
303                    matches!(
304                        ecx.tcx.struct_tail_for_codegen(pointee_ty, ecx.typing_env()).kind(),
305                        ty::Str | ty::Slice(..),
306                    ),
307                    "`ConstValue::Slice` is for slice-tailed types only, but got {}",
308                    imm.layout.ty,
309                );
310                let msg = "`op_to_const` on an immediate scalar pair must only be used on slice references to the beginning of an actual allocation";
311                let ptr = a.to_pointer(ecx).expect(msg);
312                let (prov, offset) =
313                    ptr.into_pointer_or_addr().expect(msg).prov_and_relative_offset();
314                let alloc_id = prov.alloc_id();
315                assert!(offset == abi::Size::ZERO, "{}", msg);
316                let meta = b.to_target_usize(ecx).expect(msg);
317                ConstValue::Slice { alloc_id, meta }
318            }
319            Immediate::Uninit => bug!("`Uninit` is not a valid value for {}", op.layout.ty),
320        },
321    }
322}
323
324x;#[instrument(skip(tcx), level = "debug", ret)]
325pub(crate) fn turn_into_const_value<'tcx>(
326    tcx: TyCtxt<'tcx>,
327    constant: ConstAlloc<'tcx>,
328    key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
329) -> ConstValue {
330    let cid = key.value;
331    let def_id = cid.instance.def.def_id();
332    let is_static = tcx.is_static(def_id);
333    // This is just accessing an already computed constant, so no need to check alignment here.
334    let ecx = mk_eval_cx_to_read_const_val(
335        tcx,
336        tcx.def_span(key.value.instance.def_id()),
337        key.typing_env,
338        CanAccessMutGlobal::from(is_static),
339    );
340
341    let mplace = ecx.raw_const_to_mplace(constant).expect(
342        "can only fail if layout computation failed, \
343        which should have given a good error before ever invoking this function",
344    );
345    assert!(
346        !is_static || cid.promoted.is_some(),
347        "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead"
348    );
349
350    // Turn this into a proper constant.
351    op_to_const(&ecx, &mplace.into(), /* for diagnostics */ false)
352}
353
354#[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(354u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&["key"],
                                        ::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};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&key)
                                                            as &dyn 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")]
355pub fn eval_to_const_value_raw_provider<'tcx>(
356    tcx: TyCtxt<'tcx>,
357    key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
358) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
359    crate::assert_typing_mode(key.typing_env.typing_mode());
360
361    if let Some((value, _ty)) = tcx.trivial_const(key.value.instance.def_id()) {
362        return Ok(value);
363    }
364
365    if let Some(retry) =
366        retry_codegen_mode_with_postanalysis(key, |key| tcx.eval_to_const_value_raw(key))
367    {
368        return retry;
369    }
370
371    tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
372}
373
374#[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(374u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&["def_id"],
                                        ::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};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&def_id)
                                                            as &dyn 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")]
375pub fn eval_static_initializer_provider<'tcx>(
376    tcx: TyCtxt<'tcx>,
377    def_id: LocalDefId,
378) -> ::rustc_middle::mir::interpret::EvalStaticInitializerRawResult<'tcx> {
379    assert!(tcx.is_static(def_id.to_def_id()));
380
381    let instance = ty::Instance::mono(tcx, def_id.to_def_id());
382    let cid = rustc_middle::mir::interpret::GlobalId { instance, promoted: None };
383    eval_in_interpreter(tcx, cid, ty::TypingEnv::fully_monomorphized())
384}
385
386pub trait InterpretationResult<'tcx> {
387    /// This function takes the place where the result of the evaluation is stored
388    /// and prepares it for returning it in the appropriate format needed by the specific
389    /// evaluation query.
390    fn make_result(
391        mplace: MPlaceTy<'tcx>,
392        ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>,
393    ) -> Self;
394}
395
396impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> {
397    fn make_result(
398        mplace: MPlaceTy<'tcx>,
399        _ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>,
400    ) -> Self {
401        ConstAlloc { alloc_id: mplace.ptr().provenance.unwrap().alloc_id(), ty: mplace.layout.ty }
402    }
403}
404
405#[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(405u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_const_eval::const_eval::eval_queries"),
                                    ::tracing_core::field::FieldSet::new(&["key"],
                                        ::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};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&key)
                                                            as &dyn 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:428",
                                        "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(428u32),
                                        ::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};
                                let mut iter = __CALLSITE.metadata().fields().iter();
                                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&format_args!("const eval: {0:?} ({1})",
                                                                    key, instance) as &dyn Value))])
                            });
                    } else { ; }
                };
            }
            eval_in_interpreter(tcx, key.value, key.typing_env)
        }
    }
}#[instrument(skip(tcx), level = "debug")]
406pub fn eval_to_allocation_raw_provider<'tcx>(
407    tcx: TyCtxt<'tcx>,
408    key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
409) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
410    crate::assert_typing_mode(key.typing_env.typing_mode());
411    if let Some(retry) =
412        retry_codegen_mode_with_postanalysis(key, |key| tcx.eval_to_allocation_raw(key))
413    {
414        return retry;
415    }
416
417    // This shouldn't be used for statics, since statics are conceptually places,
418    // not values -- so what we do here could break pointer identity.
419    assert!(key.value.promoted.is_some() || !tcx.is_static(key.value.instance.def_id()));
420
421    if cfg!(debug_assertions) {
422        // Make sure we format the instance even if we do not print it.
423        // This serves as a regression test against an ICE on printing.
424        // The next two lines concatenated contain some discussion:
425        // https://rust-lang.zulipchat.com/#narrow/stream/146212-t-compiler.2Fconst-eval/
426        // subject/anon_const_instance_printing/near/135980032
427        let instance = with_no_trimmed_paths!(key.value.instance.to_string());
428        trace!("const eval: {:?} ({})", key, instance);
429    }
430
431    eval_in_interpreter(tcx, key.value, key.typing_env)
432}
433
434fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
435    tcx: TyCtxt<'tcx>,
436    cid: GlobalId<'tcx>,
437    typing_env: ty::TypingEnv<'tcx>,
438) -> Result<R, ErrorHandled> {
439    let def = cid.instance.def.def_id();
440    // `type const` don't have bodys
441    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);
442
443    let is_static = tcx.is_static(def);
444    let mut ecx = InterpCx::new(
445        tcx,
446        tcx.def_span(def),
447        typing_env,
448        // Statics (and promoteds inside statics) may access mutable global memory, because unlike consts
449        // they do not have to behave "as if" they were evaluated at runtime.
450        // For consts however we want to ensure they behave "as if" they were evaluated at runtime,
451        // so we have to reject reading mutable global memory.
452        CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error),
453    );
454
455    let result = if let Some((value, ty)) = tcx.trivial_const(def) {
456        eval_trivial_const_using_ecx(&mut ecx, cid, value, ty)
457    } else {
458        ecx.load_mir(cid.instance.def, cid.promoted)
459            .and_then(|body| eval_body_using_ecx(&mut ecx, cid, body))
460    };
461    result.report_err().map_err(|error| report_eval_error(&ecx, cid, error))
462}
463
464#[inline(always)]
465fn const_validate_mplace<'tcx>(
466    ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>,
467    mplace: &MPlaceTy<'tcx>,
468    cid: GlobalId<'tcx>,
469) -> Result<(), ErrorHandled> {
470    let alloc_id = mplace.ptr().provenance.unwrap().alloc_id();
471    let mut ref_tracking = RefTracking::new(mplace.clone(), mplace.layout.ty);
472    let mut inner = false;
473    while let Some((mplace, path)) = ref_tracking.next() {
474        let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {
475            _ if cid.promoted.is_some() => CtfeValidationMode::Promoted,
476            Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
477            None => {
478                // This is a normal `const` (not promoted).
479                // The outermost allocation is always only copied, so having `UnsafeCell` in there
480                // is okay despite them being in immutable memory.
481                CtfeValidationMode::Const { allow_immutable_unsafe_cell: !inner }
482            }
483        };
484        ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)
485            .report_err()
486            // Instead of just reporting the `InterpError` via the usual machinery, we give a more targeted
487            // error about the validation failure.
488            .map_err(|error| report_validation_error(&ecx, cid, error, alloc_id))?;
489        inner = true;
490    }
491
492    Ok(())
493}
494
495#[inline(never)]
496fn report_eval_error<'tcx>(
497    ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>,
498    cid: GlobalId<'tcx>,
499    error: InterpErrorInfo<'tcx>,
500) -> ErrorHandled {
501    let (error, backtrace) = error.into_parts();
502    backtrace.print_backtrace();
503
504    super::report(ecx, error, |diag, span, frames| {
505        let num_frames = frames.len();
506        diag.span_label(
507            span,
508            ::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!(
509                "evaluation of `{instance}` failed {where_}",
510                instance = with_no_trimmed_paths!(cid.instance.to_string()),
511                where_ = if num_frames == 0 { "here" } else { "inside this call" },
512            ),
513        );
514        for frame in frames {
515            diag.subdiagnostic(frame);
516        }
517    })
518}
519
520#[inline(never)]
521fn report_validation_error<'tcx>(
522    ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>,
523    cid: GlobalId<'tcx>,
524    error: InterpErrorInfo<'tcx>,
525    alloc_id: AllocId,
526) -> ErrorHandled {
527    if !#[allow(non_exhaustive_omitted_patterns)] match error.kind() {
    InterpErrorKind::UndefinedBehavior(_) => true,
    _ => false,
}matches!(error.kind(), InterpErrorKind::UndefinedBehavior(_)) {
528        // Some other error happened during validation, e.g. an unsupported operation.
529        return report_eval_error(ecx, cid, error);
530    }
531
532    let (error, backtrace) = error.into_parts();
533    backtrace.print_backtrace();
534
535    let bytes = ecx.print_alloc_bytes_for_diagnostics(alloc_id);
536    let info = ecx.get_alloc_info(alloc_id);
537    let raw_bytes =
538        diagnostics::RawBytesNote { size: info.size.bytes(), align: info.align.bytes(), bytes };
539
540    crate::const_eval::report(ecx, error, move |diag, span, frames| {
541        diag.span_label(span, "it is undefined behavior to use this value");
542        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.");
543        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
544        diag.subdiagnostic(raw_bytes);
545    })
546}