Skip to main content

rustc_middle/mir/
consts.rs

1use std::fmt::{self, Debug, Display, Formatter};
2
3use rustc_abi::{HasDataLayout, Size};
4use rustc_hir::def_id::DefId;
5use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
6use rustc_span::{DUMMY_SP, RemapPathScopeComponents, Span, Symbol};
7use rustc_type_ir::TypeVisitableExt;
8
9use super::interpret::ReportedErrorInfo;
10use crate::mir::interpret::{AllocId, AllocRange, ErrorHandled, GlobalAlloc, Scalar, alloc_range};
11use crate::mir::{Promoted, pretty_print_const_value};
12use crate::ty::print::{pretty_print_const, with_no_trimmed_paths};
13use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt};
14
15///////////////////////////////////////////////////////////////////////////
16/// Evaluated Constants
17///
18/// Represents the result of const evaluation via the `eval_to_allocation` query.
19/// Not to be confused with `ConstAllocation`, which directly refers to the underlying data!
20/// Here we indirect via an `AllocId`.
21#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for ConstAlloc<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for ConstAlloc<'tcx> {
    #[inline]
    fn clone(&self) -> ConstAlloc<'tcx> {
        let _: ::core::clone::AssertParamIsClone<AllocId>;
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        *self
    }
}Clone, const _: () =
    {
        impl<'tcx, '__ctx>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_middle::ich::StableHashingContext<'__ctx>>
            for ConstAlloc<'tcx> {
            #[inline]
            fn hash_stable(&self,
                __hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                match *self {
                    ConstAlloc { alloc_id: ref __binding_0, ty: ref __binding_1
                        } => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable, const _: () =
    {
        impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
            ::rustc_serialize::Encodable<__E> for ConstAlloc<'tcx> {
            fn encode(&self, __encoder: &mut __E) {
                match *self {
                    ConstAlloc { alloc_id: ref __binding_0, ty: ref __binding_1
                        } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                }
            }
        }
    };TyEncodable, const _: () =
    {
        impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
            ::rustc_serialize::Decodable<__D> for ConstAlloc<'tcx> {
            fn decode(__decoder: &mut __D) -> Self {
                ConstAlloc {
                    alloc_id: ::rustc_serialize::Decodable::decode(__decoder),
                    ty: ::rustc_serialize::Decodable::decode(__decoder),
                }
            }
        }
    };TyDecodable, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for ConstAlloc<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "ConstAlloc",
            "alloc_id", &self.alloc_id, "ty", &&self.ty)
    }
}Debug, #[automatically_derived]
impl<'tcx> ::core::hash::Hash for ConstAlloc<'tcx> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.alloc_id, state);
        ::core::hash::Hash::hash(&self.ty, state)
    }
}Hash, #[automatically_derived]
impl<'tcx> ::core::cmp::Eq for ConstAlloc<'tcx> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<AllocId>;
        let _: ::core::cmp::AssertParamIsEq<Ty<'tcx>>;
    }
}Eq, #[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for ConstAlloc<'tcx> {
    #[inline]
    fn eq(&self, other: &ConstAlloc<'tcx>) -> bool {
        self.alloc_id == other.alloc_id && self.ty == other.ty
    }
}PartialEq)]
22pub struct ConstAlloc<'tcx> {
23    /// The value lives here, at offset 0, and that allocation definitely is an `AllocKind::Memory`
24    /// (so you can use `AllocMap::unwrap_memory`).
25    pub alloc_id: AllocId,
26    pub ty: Ty<'tcx>,
27}
28
29/// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for
30/// array length computations, enum discriminants and the pattern matching logic.
31#[derive(#[automatically_derived]
impl ::core::marker::Copy for ConstValue { }Copy, #[automatically_derived]
impl ::core::clone::Clone for ConstValue {
    #[inline]
    fn clone(&self) -> ConstValue {
        let _: ::core::clone::AssertParamIsClone<Scalar>;
        let _: ::core::clone::AssertParamIsClone<AllocId>;
        let _: ::core::clone::AssertParamIsClone<u64>;
        let _: ::core::clone::AssertParamIsClone<Size>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for ConstValue {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            ConstValue::Scalar(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Scalar",
                    &__self_0),
            ConstValue::ZeroSized =>
                ::core::fmt::Formatter::write_str(f, "ZeroSized"),
            ConstValue::Slice { alloc_id: __self_0, meta: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f, "Slice",
                    "alloc_id", __self_0, "meta", &__self_1),
            ConstValue::Indirect { alloc_id: __self_0, offset: __self_1 } =>
                ::core::fmt::Formatter::debug_struct_field2_finish(f,
                    "Indirect", "alloc_id", __self_0, "offset", &__self_1),
        }
    }
}Debug, #[automatically_derived]
impl ::core::cmp::Eq for ConstValue {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Scalar>;
        let _: ::core::cmp::AssertParamIsEq<AllocId>;
        let _: ::core::cmp::AssertParamIsEq<u64>;
        let _: ::core::cmp::AssertParamIsEq<Size>;
    }
}Eq, #[automatically_derived]
impl ::core::cmp::PartialEq for ConstValue {
    #[inline]
    fn eq(&self, other: &ConstValue) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (ConstValue::Scalar(__self_0), ConstValue::Scalar(__arg1_0))
                    => __self_0 == __arg1_0,
                (ConstValue::Slice { alloc_id: __self_0, meta: __self_1 },
                    ConstValue::Slice { alloc_id: __arg1_0, meta: __arg1_1 }) =>
                    __self_1 == __arg1_1 && __self_0 == __arg1_0,
                (ConstValue::Indirect { alloc_id: __self_0, offset: __self_1
                    }, ConstValue::Indirect {
                    alloc_id: __arg1_0, offset: __arg1_1 }) =>
                    __self_0 == __arg1_0 && __self_1 == __arg1_1,
                _ => true,
            }
    }
}PartialEq, const _: () =
    {
        impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
            ::rustc_serialize::Encodable<__E> for ConstValue {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        ConstValue::Scalar(ref __binding_0) => { 0usize }
                        ConstValue::ZeroSized => { 1usize }
                        ConstValue::Slice {
                            alloc_id: ref __binding_0, meta: ref __binding_1 } => {
                            2usize
                        }
                        ConstValue::Indirect {
                            alloc_id: ref __binding_0, offset: ref __binding_1 } => {
                            3usize
                        }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    ConstValue::Scalar(ref __binding_0) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    ConstValue::ZeroSized => {}
                    ConstValue::Slice {
                        alloc_id: ref __binding_0, meta: ref __binding_1 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                    ConstValue::Indirect {
                        alloc_id: ref __binding_0, offset: ref __binding_1 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                }
            }
        }
    };TyEncodable, const _: () =
    {
        impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
            ::rustc_serialize::Decodable<__D> for ConstValue {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => {
                        ConstValue::Scalar(::rustc_serialize::Decodable::decode(__decoder))
                    }
                    1usize => { ConstValue::ZeroSized }
                    2usize => {
                        ConstValue::Slice {
                            alloc_id: ::rustc_serialize::Decodable::decode(__decoder),
                            meta: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    3usize => {
                        ConstValue::Indirect {
                            alloc_id: ::rustc_serialize::Decodable::decode(__decoder),
                            offset: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `ConstValue`, expected 0..4, actual {0}",
                                n));
                    }
                }
            }
        }
    };TyDecodable, #[automatically_derived]
impl ::core::hash::Hash for ConstValue {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            ConstValue::Scalar(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            ConstValue::Slice { alloc_id: __self_0, meta: __self_1 } => {
                ::core::hash::Hash::hash(__self_0, state);
                ::core::hash::Hash::hash(__self_1, state)
            }
            ConstValue::Indirect { alloc_id: __self_0, offset: __self_1 } => {
                ::core::hash::Hash::hash(__self_0, state);
                ::core::hash::Hash::hash(__self_1, state)
            }
            _ => {}
        }
    }
}Hash)]
32#[derive(const _: () =
    {
        impl<'__ctx>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_middle::ich::StableHashingContext<'__ctx>>
            for ConstValue {
            #[inline]
            fn hash_stable(&self,
                __hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
                match *self {
                    ConstValue::Scalar(ref __binding_0) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                    }
                    ConstValue::ZeroSized => {}
                    ConstValue::Slice {
                        alloc_id: ref __binding_0, meta: ref __binding_1 } => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                    }
                    ConstValue::Indirect {
                        alloc_id: ref __binding_0, offset: ref __binding_1 } => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable)]
33pub enum ConstValue {
34    /// Used for types with `layout::abi::Scalar` ABI.
35    ///
36    /// Not using the enum `Value` to encode that this must not be `Uninit`.
37    Scalar(Scalar),
38
39    /// Only for ZSTs.
40    ZeroSized,
41
42    /// Used for references to unsized types with slice tail.
43    ///
44    /// This is worth an optimized representation since Rust has literals of type `&str` and
45    /// `&[u8]`. Not having to indirect those through an `AllocId` (or two, if we used `Indirect`)
46    /// has shown measurable performance improvements on stress tests. We then reuse this
47    /// optimization for slice-tail types more generally during valtree-to-constval conversion.
48    Slice {
49        /// The allocation storing the slice contents.
50        /// This always points to the beginning of the allocation.
51        alloc_id: AllocId,
52        /// The metadata field of the reference.
53        /// This is a "target usize", so we use `u64` as in the interpreter.
54        meta: u64,
55    },
56
57    /// A value not representable by the other variants; needs to be stored in-memory.
58    ///
59    /// Must *not* be used for scalars or ZST, but having `&str` or other slices in this variant is fine.
60    Indirect {
61        /// The backing memory of the value. May contain more memory than needed for just the value
62        /// if this points into some other larger ConstValue.
63        ///
64        /// We use an `AllocId` here instead of a `ConstAllocation<'tcx>` to make sure that when a
65        /// raw constant (which is basically just an `AllocId`) is turned into a `ConstValue` and
66        /// back, we can preserve the original `AllocId`.
67        alloc_id: AllocId,
68        /// Offset into `alloc`
69        offset: Size,
70    },
71}
72
73#[cfg(target_pointer_width = "64")]
74const _: [(); 24] = [(); ::std::mem::size_of::<ConstValue>()];rustc_data_structures::static_assert_size!(ConstValue, 24);
75
76impl ConstValue {
77    #[inline]
78    pub fn try_to_scalar(&self) -> Option<Scalar> {
79        match *self {
80            ConstValue::Indirect { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None,
81            ConstValue::Scalar(val) => Some(val),
82        }
83    }
84
85    pub fn try_to_scalar_int(&self) -> Option<ScalarInt> {
86        self.try_to_scalar()?.try_to_scalar_int().ok()
87    }
88
89    pub fn try_to_bits(&self, size: Size) -> Option<u128> {
90        Some(self.try_to_scalar_int()?.to_bits(size))
91    }
92
93    pub fn try_to_bool(&self) -> Option<bool> {
94        self.try_to_scalar_int()?.try_into().ok()
95    }
96
97    pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Option<u64> {
98        Some(self.try_to_scalar_int()?.to_target_usize(tcx))
99    }
100
101    pub fn try_to_bits_for_ty<'tcx>(
102        &self,
103        tcx: TyCtxt<'tcx>,
104        typing_env: ty::TypingEnv<'tcx>,
105        ty: Ty<'tcx>,
106    ) -> Option<u128> {
107        let size = tcx
108            .layout_of(typing_env.with_post_analysis_normalized(tcx).as_query_input(ty))
109            .ok()?
110            .size;
111        self.try_to_bits(size)
112    }
113
114    pub fn from_bool(b: bool) -> Self {
115        ConstValue::Scalar(Scalar::from_bool(b))
116    }
117
118    pub fn from_u64(i: u64) -> Self {
119        ConstValue::Scalar(Scalar::from_u64(i))
120    }
121
122    pub fn from_u128(i: u128) -> Self {
123        ConstValue::Scalar(Scalar::from_u128(i))
124    }
125
126    pub fn from_target_usize(i: u64, cx: &impl HasDataLayout) -> Self {
127        ConstValue::Scalar(Scalar::from_target_usize(i, cx))
128    }
129
130    /// Must only be called on constants of type `&str` or `&[u8]`!
131    pub fn try_get_slice_bytes_for_diagnostics<'tcx>(
132        &self,
133        tcx: TyCtxt<'tcx>,
134    ) -> Option<&'tcx [u8]> {
135        let (alloc_id, start, len) = match self {
136            ConstValue::Scalar(_) | ConstValue::ZeroSized => {
137                crate::util::bug::bug_fmt(format_args!("`try_get_slice_bytes` on non-slice constant"))bug!("`try_get_slice_bytes` on non-slice constant")
138            }
139            &ConstValue::Slice { alloc_id, meta } => (alloc_id, 0, meta),
140            &ConstValue::Indirect { alloc_id, offset } => {
141                // The reference itself is stored behind an indirection.
142                // Load the reference, and then load the actual slice contents.
143                let a = tcx.global_alloc(alloc_id).unwrap_memory().inner();
144                let ptr_size = tcx.data_layout.pointer_size();
145                if a.size() < offset + 2 * ptr_size {
146                    // (partially) dangling reference
147                    return None;
148                }
149                // Read the wide pointer components.
150                let ptr = a
151                    .read_scalar(
152                        &tcx,
153                        alloc_range(offset, ptr_size),
154                        /* read_provenance */ true,
155                    )
156                    .ok()?;
157                let ptr = ptr.to_pointer(&tcx).discard_err()?;
158                let len = a
159                    .read_scalar(
160                        &tcx,
161                        alloc_range(offset + ptr_size, ptr_size),
162                        /* read_provenance */ false,
163                    )
164                    .ok()?;
165                let len = len.to_target_usize(&tcx).discard_err()?;
166                if len == 0 {
167                    return Some(&[]);
168                }
169                // Non-empty slice, must have memory. We know this is a relative pointer.
170                let (inner_prov, offset) =
171                    ptr.into_pointer_or_addr().ok()?.prov_and_relative_offset();
172                (inner_prov.alloc_id(), offset.bytes(), len)
173            }
174        };
175
176        let data = tcx.global_alloc(alloc_id).unwrap_memory();
177
178        // This is for diagnostics only, so we are okay to use `inspect_with_uninit_and_ptr_outside_interpreter`.
179        let start = start.try_into().unwrap();
180        let end = start + usize::try_from(len).unwrap();
181        Some(data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end))
182    }
183
184    /// Check if a constant only contains uninitialized bytes.
185    pub fn all_bytes_uninit(&self, tcx: TyCtxt<'_>) -> bool {
186        let ConstValue::Indirect { alloc_id, .. } = self else {
187            return false;
188        };
189        let alloc = tcx.global_alloc(*alloc_id);
190        let GlobalAlloc::Memory(alloc) = alloc else {
191            return false;
192        };
193        let init_mask = alloc.0.init_mask();
194        let init_range = init_mask.is_range_initialized(AllocRange {
195            start: Size::ZERO,
196            size: Size::from_bytes(alloc.0.len()),
197        });
198        if let Err(range) = init_range {
199            if range.size == alloc.0.size() {
200                return true;
201            }
202        }
203        false
204    }
205}
206
207///////////////////////////////////////////////////////////////////////////
208/// Constants
209
210#[derive(#[automatically_derived]
impl<'tcx> ::core::clone::Clone for Const<'tcx> {
    #[inline]
    fn clone(&self) -> Const<'tcx> {
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<ty::Const<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<UnevaluatedConst<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<ConstValue>;
        let _: ::core::clone::AssertParamIsClone<Ty<'tcx>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::marker::Copy for Const<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for Const<'tcx> {
    #[inline]
    fn eq(&self, other: &Const<'tcx>) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (Const::Ty(__self_0, __self_1), Const::Ty(__arg1_0, __arg1_1))
                    => __self_0 == __arg1_0 && __self_1 == __arg1_1,
                (Const::Unevaluated(__self_0, __self_1),
                    Const::Unevaluated(__arg1_0, __arg1_1)) =>
                    __self_0 == __arg1_0 && __self_1 == __arg1_1,
                (Const::Val(__self_0, __self_1),
                    Const::Val(__arg1_0, __arg1_1)) =>
                    __self_0 == __arg1_0 && __self_1 == __arg1_1,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl<'tcx> ::core::cmp::Eq for Const<'tcx> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Ty<'tcx>>;
        let _: ::core::cmp::AssertParamIsEq<ty::Const<'tcx>>;
        let _: ::core::cmp::AssertParamIsEq<UnevaluatedConst<'tcx>>;
        let _: ::core::cmp::AssertParamIsEq<Ty<'tcx>>;
        let _: ::core::cmp::AssertParamIsEq<ConstValue>;
        let _: ::core::cmp::AssertParamIsEq<Ty<'tcx>>;
    }
}Eq, const _: () =
    {
        impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
            ::rustc_serialize::Encodable<__E> for Const<'tcx> {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        Const::Ty(ref __binding_0, ref __binding_1) => { 0usize }
                        Const::Unevaluated(ref __binding_0, ref __binding_1) => {
                            1usize
                        }
                        Const::Val(ref __binding_0, ref __binding_1) => { 2usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    Const::Ty(ref __binding_0, ref __binding_1) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                    Const::Unevaluated(ref __binding_0, ref __binding_1) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                    Const::Val(ref __binding_0, ref __binding_1) => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                    }
                }
            }
        }
    };TyEncodable, const _: () =
    {
        impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
            ::rustc_serialize::Decodable<__D> for Const<'tcx> {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => {
                        Const::Ty(::rustc_serialize::Decodable::decode(__decoder),
                            ::rustc_serialize::Decodable::decode(__decoder))
                    }
                    1usize => {
                        Const::Unevaluated(::rustc_serialize::Decodable::decode(__decoder),
                            ::rustc_serialize::Decodable::decode(__decoder))
                    }
                    2usize => {
                        Const::Val(::rustc_serialize::Decodable::decode(__decoder),
                            ::rustc_serialize::Decodable::decode(__decoder))
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `Const`, expected 0..3, actual {0}",
                                n));
                    }
                }
            }
        }
    };TyDecodable, #[automatically_derived]
impl<'tcx> ::core::hash::Hash for Const<'tcx> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            Const::Ty(__self_0, __self_1) => {
                ::core::hash::Hash::hash(__self_0, state);
                ::core::hash::Hash::hash(__self_1, state)
            }
            Const::Unevaluated(__self_0, __self_1) => {
                ::core::hash::Hash::hash(__self_0, state);
                ::core::hash::Hash::hash(__self_1, state)
            }
            Const::Val(__self_0, __self_1) => {
                ::core::hash::Hash::hash(__self_0, state);
                ::core::hash::Hash::hash(__self_1, state)
            }
        }
    }
}Hash, const _: () =
    {
        impl<'tcx, '__ctx>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_middle::ich::StableHashingContext<'__ctx>>
            for Const<'tcx> {
            #[inline]
            fn hash_stable(&self,
                __hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
                match *self {
                    Const::Ty(ref __binding_0, ref __binding_1) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                    }
                    Const::Unevaluated(ref __binding_0, ref __binding_1) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                    }
                    Const::Val(ref __binding_0, ref __binding_1) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for Const<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Const::Ty(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f, "Ty",
                    __self_0, &__self_1),
            Const::Unevaluated(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f,
                    "Unevaluated", __self_0, &__self_1),
            Const::Val(__self_0, __self_1) =>
                ::core::fmt::Formatter::debug_tuple_field2_finish(f, "Val",
                    __self_0, &__self_1),
        }
    }
}Debug)]
211#[derive(const _: () =
    {
        impl<'tcx>
            ::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>
            for Const<'tcx> {
            fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
                __folder: &mut __F) -> Result<Self, __F::Error> {
                Ok(match self {
                        Const::Ty(__binding_0, __binding_1) => {
                            Const::Ty(::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                                ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_1,
                                        __folder)?)
                        }
                        Const::Unevaluated(__binding_0, __binding_1) => {
                            Const::Unevaluated(::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                                ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_1,
                                        __folder)?)
                        }
                        Const::Val(__binding_0, __binding_1) => {
                            Const::Val(::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                                ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_1,
                                        __folder)?)
                        }
                    })
            }
            fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
                __folder: &mut __F) -> Self {
                match self {
                    Const::Ty(__binding_0, __binding_1) => {
                        Const::Ty(::rustc_middle::ty::TypeFoldable::fold_with(__binding_0,
                                __folder),
                            ::rustc_middle::ty::TypeFoldable::fold_with(__binding_1,
                                __folder))
                    }
                    Const::Unevaluated(__binding_0, __binding_1) => {
                        Const::Unevaluated(::rustc_middle::ty::TypeFoldable::fold_with(__binding_0,
                                __folder),
                            ::rustc_middle::ty::TypeFoldable::fold_with(__binding_1,
                                __folder))
                    }
                    Const::Val(__binding_0, __binding_1) => {
                        Const::Val(::rustc_middle::ty::TypeFoldable::fold_with(__binding_0,
                                __folder),
                            ::rustc_middle::ty::TypeFoldable::fold_with(__binding_1,
                                __folder))
                    }
                }
            }
        }
    };TypeFoldable, const _: () =
    {
        impl<'tcx>
            ::rustc_middle::ty::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>
            for Const<'tcx> {
            fn visit_with<__V: ::rustc_middle::ty::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>(&self,
                __visitor: &mut __V) -> __V::Result {
                match *self {
                    Const::Ty(ref __binding_0, ref __binding_1) => {
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_1,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                    Const::Unevaluated(ref __binding_0, ref __binding_1) => {
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_1,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                    Const::Val(ref __binding_0, ref __binding_1) => {
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_1,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                }
                <__V::Result as ::rustc_middle::ty::VisitorResult>::output()
            }
        }
    };TypeVisitable, const _: () =
    {
        impl<'tcx, '__lifted>
            ::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>
            for Const<'tcx> {
            type Lifted = Const<'__lifted>;
            fn lift_to_interner(self,
                __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>)
                -> Option<Const<'__lifted>> {
                Some(match self {
                        Const::Ty(__binding_0, __binding_1) => {
                            Const::Ty(__tcx.lift(__binding_0)?,
                                __tcx.lift(__binding_1)?)
                        }
                        Const::Unevaluated(__binding_0, __binding_1) => {
                            Const::Unevaluated(__tcx.lift(__binding_0)?,
                                __tcx.lift(__binding_1)?)
                        }
                        Const::Val(__binding_0, __binding_1) => {
                            Const::Val(__tcx.lift(__binding_0)?,
                                __tcx.lift(__binding_1)?)
                        }
                    })
            }
        }
    };Lift)]
212pub enum Const<'tcx> {
213    /// This constant came from the type system.
214    ///
215    /// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`;
216    /// this ensures that we consistently produce "clean" values without data in the padding or
217    /// anything like that.
218    ///
219    /// FIXME(BoxyUwU): We should remove this `Ty` and look up the type for params via `ParamEnv`
220    Ty(Ty<'tcx>, ty::Const<'tcx>),
221
222    /// An unevaluated mir constant which is not part of the type system.
223    ///
224    /// Note that `Ty(ty::ConstKind::Unevaluated)` and this variant are *not* identical! `Ty` will
225    /// always flow through a valtree, so all data not captured in the valtree is lost. This variant
226    /// directly uses the evaluated result of the given constant, including e.g. data stored in
227    /// padding.
228    Unevaluated(UnevaluatedConst<'tcx>, Ty<'tcx>),
229
230    /// This constant cannot go back into the type system, as it represents
231    /// something the type system cannot handle (e.g. pointers).
232    Val(ConstValue, Ty<'tcx>),
233}
234
235impl<'tcx> Const<'tcx> {
236    /// Creates an unevaluated const from a `DefId` for a const item.
237    /// The binders of the const item still need to be instantiated.
238    pub fn from_unevaluated(
239        tcx: TyCtxt<'tcx>,
240        def_id: DefId,
241    ) -> ty::EarlyBinder<'tcx, Const<'tcx>> {
242        ty::EarlyBinder::bind(Const::Unevaluated(
243            UnevaluatedConst {
244                def: def_id,
245                args: ty::GenericArgs::identity_for_item(tcx, def_id),
246                promoted: None,
247            },
248            tcx.type_of(def_id).skip_binder(),
249        ))
250    }
251
252    #[inline(always)]
253    pub fn ty(&self) -> Ty<'tcx> {
254        match self {
255            Const::Ty(ty, ct) => {
256                match ct.kind() {
257                    // Dont use the outer ty as on invalid code we can wind up with them not being the same.
258                    // this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir
259                    // was originally `({N: usize} + 1_usize)` under `generic_const_exprs`.
260                    ty::ConstKind::Value(cv) => cv.ty,
261                    _ => *ty,
262                }
263            }
264            Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty,
265        }
266    }
267
268    /// Determines whether we need to add this const to `required_consts`. This is the case if and
269    /// only if evaluating it may error.
270    #[inline]
271    pub fn is_required_const(&self) -> bool {
272        match self {
273            Const::Ty(_, c) => match c.kind() {
274                ty::ConstKind::Value(_) => false, // already a value, cannot error
275                _ => true,
276            },
277            Const::Val(..) => false, // already a value, cannot error
278            Const::Unevaluated(..) => true,
279        }
280    }
281
282    #[inline]
283    pub fn try_to_scalar(self) -> Option<Scalar> {
284        match self {
285            Const::Ty(_, c) => c.try_to_scalar(),
286            Const::Val(val, _) => val.try_to_scalar(),
287            Const::Unevaluated(..) => None,
288        }
289    }
290
291    #[inline]
292    pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
293        // This is equivalent to `self.try_to_scalar()?.try_to_int().ok()`, but measurably faster.
294        match self {
295            Const::Val(ConstValue::Scalar(Scalar::Int(x)), _) => Some(x),
296            Const::Ty(_, c) => c.try_to_leaf(),
297            _ => None,
298        }
299    }
300
301    #[inline]
302    pub fn try_to_bits(self, size: Size) -> Option<u128> {
303        Some(self.try_to_scalar_int()?.to_bits(size))
304    }
305
306    #[inline]
307    pub fn try_to_bool(self) -> Option<bool> {
308        self.try_to_scalar_int()?.try_into().ok()
309    }
310
311    #[inline]
312    pub fn eval(
313        self,
314        tcx: TyCtxt<'tcx>,
315        typing_env: ty::TypingEnv<'tcx>,
316        span: Span,
317    ) -> Result<ConstValue, ErrorHandled> {
318        match self {
319            Const::Ty(_, c) => {
320                if c.has_non_region_param() {
321                    return Err(ErrorHandled::TooGeneric(span));
322                }
323
324                match c.kind() {
325                    ConstKind::Value(cv) => Ok(tcx.valtree_to_const_val(cv)),
326                    ConstKind::Expr(_) => {
327                        crate::util::bug::bug_fmt(format_args!("Normalization of `ty::ConstKind::Expr` is unimplemented"))bug!("Normalization of `ty::ConstKind::Expr` is unimplemented")
328                    }
329                    _ => Err(ReportedErrorInfo::non_const_eval_error(
330                        tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body"),
331                    )
332                    .into()),
333                }
334            }
335            Const::Unevaluated(uneval, _) => {
336                // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
337                tcx.const_eval_resolve(typing_env, uneval, span)
338            }
339            Const::Val(val, _) => Ok(val),
340        }
341    }
342
343    #[inline]
344    pub fn try_eval_scalar(
345        self,
346        tcx: TyCtxt<'tcx>,
347        typing_env: ty::TypingEnv<'tcx>,
348    ) -> Option<Scalar> {
349        if let Const::Ty(_, c) = self {
350            // We don't evaluate anything for type system constants as normalizing
351            // the MIR will handle this for us
352            c.try_to_scalar()
353        } else {
354            self.eval(tcx, typing_env, DUMMY_SP).ok()?.try_to_scalar()
355        }
356    }
357
358    #[inline]
359    pub fn try_eval_scalar_int(
360        self,
361        tcx: TyCtxt<'tcx>,
362        typing_env: ty::TypingEnv<'tcx>,
363    ) -> Option<ScalarInt> {
364        self.try_eval_scalar(tcx, typing_env)?.try_to_scalar_int().ok()
365    }
366
367    #[inline]
368    pub fn try_eval_bits(
369        &self,
370        tcx: TyCtxt<'tcx>,
371        typing_env: ty::TypingEnv<'tcx>,
372    ) -> Option<u128> {
373        let int = self.try_eval_scalar_int(tcx, typing_env)?;
374        let size = tcx
375            .layout_of(typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty()))
376            .ok()?
377            .size;
378        Some(int.to_bits(size))
379    }
380
381    /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
382    #[inline]
383    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> u128 {
384        self.try_eval_bits(tcx, typing_env)
385            .unwrap_or_else(|| crate::util::bug::bug_fmt(format_args!("expected bits of {0:#?}, got {1:#?}",
        self.ty(), self))bug!("expected bits of {:#?}, got {:#?}", self.ty(), self))
386    }
387
388    #[inline]
389    pub fn try_eval_target_usize(
390        self,
391        tcx: TyCtxt<'tcx>,
392        typing_env: ty::TypingEnv<'tcx>,
393    ) -> Option<u64> {
394        Some(self.try_eval_scalar_int(tcx, typing_env)?.to_target_usize(tcx))
395    }
396
397    #[inline]
398    /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
399    pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> u64 {
400        self.try_eval_target_usize(tcx, typing_env)
401            .unwrap_or_else(|| crate::util::bug::bug_fmt(format_args!("expected usize, got {0:#?}", self))bug!("expected usize, got {:#?}", self))
402    }
403
404    #[inline]
405    pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<bool> {
406        self.try_eval_scalar_int(tcx, typing_env)?.try_into().ok()
407    }
408
409    #[inline]
410    pub fn from_value(val: ConstValue, ty: Ty<'tcx>) -> Self {
411        Self::Val(val, ty)
412    }
413
414    #[inline]
415    pub fn from_ty_value(tcx: TyCtxt<'tcx>, val: ty::Value<'tcx>) -> Self {
416        Self::Ty(val.ty, ty::Const::new_value(tcx, val.valtree, val.ty))
417    }
418
419    pub fn from_bits(
420        tcx: TyCtxt<'tcx>,
421        bits: u128,
422        typing_env: ty::TypingEnv<'tcx>,
423        ty: Ty<'tcx>,
424    ) -> Self {
425        let size = tcx
426            .layout_of(typing_env.as_query_input(ty))
427            .unwrap_or_else(|e| crate::util::bug::bug_fmt(format_args!("could not compute layout for {0:?}: {1:?}",
        ty, e))bug!("could not compute layout for {ty:?}: {e:?}"))
428            .size;
429        let cv = ConstValue::Scalar(Scalar::from_uint(bits, size));
430
431        Self::Val(cv, ty)
432    }
433
434    #[inline]
435    pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
436        let cv = ConstValue::from_bool(v);
437        Self::Val(cv, tcx.types.bool)
438    }
439
440    #[inline]
441    pub fn zero_sized(ty: Ty<'tcx>) -> Self {
442        let cv = ConstValue::ZeroSized;
443        Self::Val(cv, ty)
444    }
445
446    pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
447        let ty = tcx.types.usize;
448        let typing_env = ty::TypingEnv::fully_monomorphized();
449        Self::from_bits(tcx, n as u128, typing_env, ty)
450    }
451
452    #[inline]
453    pub fn from_scalar(_tcx: TyCtxt<'tcx>, s: Scalar, ty: Ty<'tcx>) -> Self {
454        let val = ConstValue::Scalar(s);
455        Self::Val(val, ty)
456    }
457}
458
459/// An unevaluated (potentially generic) constant used in MIR.
460#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for UnevaluatedConst<'tcx> { }Copy, #[automatically_derived]
impl<'tcx> ::core::clone::Clone for UnevaluatedConst<'tcx> {
    #[inline]
    fn clone(&self) -> UnevaluatedConst<'tcx> {
        let _: ::core::clone::AssertParamIsClone<DefId>;
        let _: ::core::clone::AssertParamIsClone<GenericArgsRef<'tcx>>;
        let _: ::core::clone::AssertParamIsClone<Option<Promoted>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for UnevaluatedConst<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field3_finish(f,
            "UnevaluatedConst", "def", &self.def, "args", &self.args,
            "promoted", &&self.promoted)
    }
}Debug, #[automatically_derived]
impl<'tcx> ::core::cmp::Eq for UnevaluatedConst<'tcx> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_receiver_is_total_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<DefId>;
        let _: ::core::cmp::AssertParamIsEq<GenericArgsRef<'tcx>>;
        let _: ::core::cmp::AssertParamIsEq<Option<Promoted>>;
    }
}Eq, #[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for UnevaluatedConst<'tcx> {
    #[inline]
    fn eq(&self, other: &UnevaluatedConst<'tcx>) -> bool {
        self.def == other.def && self.args == other.args &&
            self.promoted == other.promoted
    }
}PartialEq, const _: () =
    {
        impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
            ::rustc_serialize::Encodable<__E> for UnevaluatedConst<'tcx> {
            fn encode(&self, __encoder: &mut __E) {
                match *self {
                    UnevaluatedConst {
                        def: ref __binding_0,
                        args: ref __binding_1,
                        promoted: ref __binding_2 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_1,
                            __encoder);
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_2,
                            __encoder);
                    }
                }
            }
        }
    };TyEncodable, const _: () =
    {
        impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
            ::rustc_serialize::Decodable<__D> for UnevaluatedConst<'tcx> {
            fn decode(__decoder: &mut __D) -> Self {
                UnevaluatedConst {
                    def: ::rustc_serialize::Decodable::decode(__decoder),
                    args: ::rustc_serialize::Decodable::decode(__decoder),
                    promoted: ::rustc_serialize::Decodable::decode(__decoder),
                }
            }
        }
    };TyDecodable)]
461#[derive(#[automatically_derived]
impl<'tcx> ::core::hash::Hash for UnevaluatedConst<'tcx> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.def, state);
        ::core::hash::Hash::hash(&self.args, state);
        ::core::hash::Hash::hash(&self.promoted, state)
    }
}Hash, const _: () =
    {
        impl<'tcx, '__ctx>
            ::rustc_data_structures::stable_hasher::HashStable<::rustc_middle::ich::StableHashingContext<'__ctx>>
            for UnevaluatedConst<'tcx> {
            #[inline]
            fn hash_stable(&self,
                __hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                match *self {
                    UnevaluatedConst {
                        def: ref __binding_0,
                        args: ref __binding_1,
                        promoted: ref __binding_2 } => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                        { __binding_2.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable, const _: () =
    {
        impl<'tcx>
            ::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>
            for UnevaluatedConst<'tcx> {
            fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
                __folder: &mut __F) -> Result<Self, __F::Error> {
                Ok(match self {
                        UnevaluatedConst {
                            def: __binding_0, args: __binding_1, promoted: __binding_2 }
                            => {
                            UnevaluatedConst {
                                def: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_0,
                                        __folder)?,
                                args: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_1,
                                        __folder)?,
                                promoted: ::rustc_middle::ty::TypeFoldable::try_fold_with(__binding_2,
                                        __folder)?,
                            }
                        }
                    })
            }
            fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(self,
                __folder: &mut __F) -> Self {
                match self {
                    UnevaluatedConst {
                        def: __binding_0, args: __binding_1, promoted: __binding_2 }
                        => {
                        UnevaluatedConst {
                            def: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_0,
                                __folder),
                            args: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_1,
                                __folder),
                            promoted: ::rustc_middle::ty::TypeFoldable::fold_with(__binding_2,
                                __folder),
                        }
                    }
                }
            }
        }
    };TypeFoldable, const _: () =
    {
        impl<'tcx>
            ::rustc_middle::ty::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>
            for UnevaluatedConst<'tcx> {
            fn visit_with<__V: ::rustc_middle::ty::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>(&self,
                __visitor: &mut __V) -> __V::Result {
                match *self {
                    UnevaluatedConst {
                        def: ref __binding_0,
                        args: ref __binding_1,
                        promoted: ref __binding_2 } => {
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_0,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_1,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                        {
                            match ::rustc_middle::ty::VisitorResult::branch(::rustc_middle::ty::TypeVisitable::visit_with(__binding_2,
                                        __visitor)) {
                                ::core::ops::ControlFlow::Continue(()) => {}
                                ::core::ops::ControlFlow::Break(r) => {
                                    return ::rustc_middle::ty::VisitorResult::from_residual(r);
                                }
                            }
                        }
                    }
                }
                <__V::Result as ::rustc_middle::ty::VisitorResult>::output()
            }
        }
    };TypeVisitable, const _: () =
    {
        impl<'tcx, '__lifted>
            ::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>
            for UnevaluatedConst<'tcx> {
            type Lifted = UnevaluatedConst<'__lifted>;
            fn lift_to_interner(self,
                __tcx: ::rustc_middle::ty::TyCtxt<'__lifted>)
                -> Option<UnevaluatedConst<'__lifted>> {
                Some(match self {
                        UnevaluatedConst {
                            def: __binding_0, args: __binding_1, promoted: __binding_2 }
                            => {
                            UnevaluatedConst {
                                def: __tcx.lift(__binding_0)?,
                                args: __tcx.lift(__binding_1)?,
                                promoted: __tcx.lift(__binding_2)?,
                            }
                        }
                    })
            }
        }
    };Lift)]
462pub struct UnevaluatedConst<'tcx> {
463    pub def: DefId,
464    pub args: GenericArgsRef<'tcx>,
465    pub promoted: Option<Promoted>,
466}
467
468impl<'tcx> UnevaluatedConst<'tcx> {
469    #[inline]
470    pub fn shrink(self) -> ty::UnevaluatedConst<'tcx> {
471        match (&self.promoted, &None) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(self.promoted, None);
472        ty::UnevaluatedConst { def: self.def, args: self.args }
473    }
474}
475
476impl<'tcx> UnevaluatedConst<'tcx> {
477    #[inline]
478    pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
479        UnevaluatedConst { def, args, promoted: Default::default() }
480    }
481
482    #[inline]
483    pub fn from_instance(instance: ty::Instance<'tcx>) -> Self {
484        UnevaluatedConst::new(instance.def_id(), instance.args)
485    }
486}
487
488impl<'tcx> Display for Const<'tcx> {
489    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
490        match *self {
491            Const::Ty(_, c) => pretty_print_const(c, fmt, true),
492            Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
493            // FIXME(valtrees): Correctly print mir constants.
494            Const::Unevaluated(c, _ty) => {
495                ty::tls::with(move |tcx| {
496                    let c = tcx.lift(c).unwrap();
497                    // Matches `GlobalId` printing.
498                    let instance =
499                        {
    let _guard = NoTrimmedGuard::new();
    tcx.def_path_str_with_args(c.def, c.args)
}with_no_trimmed_paths!(tcx.def_path_str_with_args(c.def, c.args));
500                    fmt.write_fmt(format_args!("{0}", instance))write!(fmt, "{instance}")?;
501                    if let Some(promoted) = c.promoted {
502                        fmt.write_fmt(format_args!("::{0:?}", promoted))write!(fmt, "::{promoted:?}")?;
503                    }
504                    Ok(())
505                })
506            }
507        }
508    }
509}
510
511///////////////////////////////////////////////////////////////////////////
512// Const-related utilities
513
514impl<'tcx> TyCtxt<'tcx> {
515    pub fn span_as_caller_location(self, span: Span) -> ConstValue {
516        let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
517        let caller = self.sess.source_map().lookup_char_pos(topmost.lo());
518        self.const_caller_location(
519            Symbol::intern(
520                &caller.file.name.display(RemapPathScopeComponents::MACRO).to_string_lossy(),
521            ),
522            caller.line as u32,
523            caller.col_display as u32 + 1,
524        )
525    }
526}