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::{Lift, StableHash, 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]
#[doc(hidden)]
unsafe impl<'tcx> ::core::clone::TrivialClone for ConstAlloc<'tcx> { }
#[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> ::rustc_data_structures::stable_hash::StableHash for
            ConstAlloc<'tcx> {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                match *self {
                    ConstAlloc { alloc_id: ref __binding_0, ty: ref __binding_1
                        } => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash, const _: () =
    {
        impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
            ::rustc_serialize::Encodable<__E> for ConstAlloc<'tcx> {
            fn encode(&self, __encoder: &mut __E) {
                let ConstAlloc {
                        alloc_id: ref __binding_0, ty: ref __binding_1 } = *self;
                ::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::cmp::Eq for ConstAlloc<'tcx> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<AllocId>;
        let _: ::core::cmp::AssertParamIsEq<Ty<'tcx>>;
    }
}Eq, #[automatically_derived]
impl<'tcx> ::core::marker::StructuralPartialEq for ConstAlloc<'tcx> { }
#[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]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ConstValue { }
#[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_fields_are_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::marker::StructuralPartialEq for ConstValue { }
#[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 ::rustc_data_structures::stable_hash::StableHash for ConstValue {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    ConstValue::Scalar(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                    ConstValue::ZeroSized => {}
                    ConstValue::Slice {
                        alloc_id: ref __binding_0, meta: ref __binding_1 } => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                    ConstValue::Indirect {
                        alloc_id: ref __binding_0, offset: ref __binding_1 } => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash)]
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);
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]
#[doc(hidden)]
unsafe impl<'tcx> ::core::clone::TrivialClone for Const<'tcx> { }
#[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::marker::StructuralPartialEq for Const<'tcx> { }
#[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_fields_are_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> ::rustc_data_structures::stable_hash::StableHash for
            Const<'tcx> {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    Const::Ty(ref __binding_0, ref __binding_1) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                    Const::Unevaluated(ref __binding_0, ref __binding_1) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                    Const::Val(ref __binding_0, ref __binding_1) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash, #[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>)
                -> Const<'__lifted> {
                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::Alias)` 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(
243            tcx,
244            Const::Unevaluated(
245                UnevaluatedConst {
246                    def: def_id,
247                    args: ty::GenericArgs::identity_for_item(tcx, def_id),
248                    promoted: None,
249                },
250                tcx.type_of(def_id).skip_binder(),
251            ),
252        )
253    }
254
255    #[inline(always)]
256    pub fn ty(&self) -> Ty<'tcx> {
257        match self {
258            Const::Ty(ty, ct) => {
259                match ct.kind() {
260                    // Dont use the outer ty as on invalid code we can wind up with them not being the same.
261                    // this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir
262                    // was originally `({N: usize} + 1_usize)` under `generic_const_exprs`.
263                    ty::ConstKind::Value(cv) => cv.ty,
264                    _ => *ty,
265                }
266            }
267            Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty,
268        }
269    }
270
271    /// Determines whether we need to add this const to `required_consts`. This is the case if and
272    /// only if evaluating it may error.
273    #[inline]
274    pub fn is_required_const(&self) -> bool {
275        match self {
276            Const::Ty(_, c) => match c.kind() {
277                ty::ConstKind::Value(_) => false, // already a value, cannot error
278                _ => true,
279            },
280            Const::Val(..) => false, // already a value, cannot error
281            Const::Unevaluated(..) => true,
282        }
283    }
284
285    #[inline]
286    pub fn try_to_scalar(self) -> Option<Scalar> {
287        match self {
288            Const::Ty(_, c) => c.try_to_scalar(),
289            Const::Val(val, _) => val.try_to_scalar(),
290            Const::Unevaluated(..) => None,
291        }
292    }
293
294    #[inline]
295    pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
296        // This is equivalent to `self.try_to_scalar()?.try_to_int().ok()`, but measurably faster.
297        match self {
298            Const::Val(ConstValue::Scalar(Scalar::Int(x)), _) => Some(x),
299            Const::Ty(_, c) => c.try_to_leaf(),
300            _ => None,
301        }
302    }
303
304    #[inline]
305    pub fn try_to_bits(self, size: Size) -> Option<u128> {
306        Some(self.try_to_scalar_int()?.to_bits(size))
307    }
308
309    #[inline]
310    pub fn try_to_bool(self) -> Option<bool> {
311        self.try_to_scalar_int()?.try_into().ok()
312    }
313
314    #[inline]
315    pub fn eval(
316        self,
317        tcx: TyCtxt<'tcx>,
318        typing_env: ty::TypingEnv<'tcx>,
319        span: Span,
320    ) -> Result<ConstValue, ErrorHandled> {
321        match self {
322            Const::Ty(_, c) => {
323                if let Err(e) = c.error_reported() {
324                    return Err(ReportedErrorInfo::non_const_eval_error(e).into());
325                }
326
327                // FIXME(generic_const_exprs): We shouldn't encounter placeholders here
328                // and could change this to ICE when encountering them instead.
329                if c.has_non_region_param() || c.has_non_region_placeholders() {
330                    return Err(ErrorHandled::TooGeneric(span));
331                }
332
333                match c.kind() {
334                    ConstKind::Value(cv) => Ok(tcx.valtree_to_const_val(cv)),
335                    ConstKind::Expr(_) => {
336                        crate::util::bug::bug_fmt(format_args!("Normalization of `ty::ConstKind::Expr` is unimplemented"))bug!("Normalization of `ty::ConstKind::Expr` is unimplemented")
337                    }
338                    _ => Err(ReportedErrorInfo::non_const_eval_error(
339                        tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body"),
340                    )
341                    .into()),
342                }
343            }
344            Const::Unevaluated(uneval, _) => {
345                // FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
346                tcx.const_eval_resolve(typing_env, uneval, span)
347            }
348            Const::Val(val, _ty) => Ok(val),
349        }
350    }
351
352    #[inline]
353    pub fn try_eval_scalar(
354        self,
355        tcx: TyCtxt<'tcx>,
356        typing_env: ty::TypingEnv<'tcx>,
357    ) -> Option<Scalar> {
358        if let Const::Ty(_, c) = self {
359            // We don't evaluate anything for type system constants as normalizing
360            // the MIR will handle this for us
361            c.try_to_scalar()
362        } else {
363            self.eval(tcx, typing_env, DUMMY_SP).ok()?.try_to_scalar()
364        }
365    }
366
367    #[inline]
368    pub fn try_eval_scalar_int(
369        self,
370        tcx: TyCtxt<'tcx>,
371        typing_env: ty::TypingEnv<'tcx>,
372    ) -> Option<ScalarInt> {
373        self.try_eval_scalar(tcx, typing_env)?.try_to_scalar_int().ok()
374    }
375
376    #[inline]
377    pub fn try_eval_bits(
378        &self,
379        tcx: TyCtxt<'tcx>,
380        typing_env: ty::TypingEnv<'tcx>,
381    ) -> Option<u128> {
382        let int = self.try_eval_scalar_int(tcx, typing_env)?;
383        let size = tcx
384            .layout_of(typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty()))
385            .ok()?
386            .size;
387        Some(int.to_bits(size))
388    }
389
390    /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
391    #[inline]
392    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> u128 {
393        self.try_eval_bits(tcx, typing_env)
394            .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))
395    }
396
397    #[inline]
398    pub fn try_eval_target_usize(
399        self,
400        tcx: TyCtxt<'tcx>,
401        typing_env: ty::TypingEnv<'tcx>,
402    ) -> Option<u64> {
403        Some(self.try_eval_scalar_int(tcx, typing_env)?.to_target_usize(tcx))
404    }
405
406    #[inline]
407    /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
408    pub fn eval_target_usize(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> u64 {
409        self.try_eval_target_usize(tcx, typing_env)
410            .unwrap_or_else(|| crate::util::bug::bug_fmt(format_args!("expected usize, got {0:#?}", self))bug!("expected usize, got {:#?}", self))
411    }
412
413    #[inline]
414    pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> Option<bool> {
415        self.try_eval_scalar_int(tcx, typing_env)?.try_into().ok()
416    }
417
418    #[inline]
419    pub fn from_value(val: ConstValue, ty: Ty<'tcx>) -> Self {
420        Self::Val(val, ty)
421    }
422
423    #[inline]
424    pub fn from_ty_value(tcx: TyCtxt<'tcx>, val: ty::Value<'tcx>) -> Self {
425        Self::Ty(val.ty, ty::Const::new_value(tcx, val.valtree, val.ty))
426    }
427
428    pub fn from_bits(
429        tcx: TyCtxt<'tcx>,
430        bits: u128,
431        typing_env: ty::TypingEnv<'tcx>,
432        ty: Ty<'tcx>,
433    ) -> Self {
434        let size = tcx
435            .layout_of(typing_env.as_query_input(ty))
436            .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:?}"))
437            .size;
438        let cv = ConstValue::Scalar(Scalar::from_uint(bits, size));
439
440        Self::Val(cv, ty)
441    }
442
443    #[inline]
444    pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
445        let cv = ConstValue::from_bool(v);
446        Self::Val(cv, tcx.types.bool)
447    }
448
449    #[inline]
450    pub fn zero_sized(ty: Ty<'tcx>) -> Self {
451        let cv = ConstValue::ZeroSized;
452        Self::Val(cv, ty)
453    }
454
455    pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
456        let ty = tcx.types.usize;
457        let typing_env = ty::TypingEnv::fully_monomorphized();
458        Self::from_bits(tcx, n as u128, typing_env, ty)
459    }
460
461    #[inline]
462    pub fn from_scalar(_tcx: TyCtxt<'tcx>, s: Scalar, ty: Ty<'tcx>) -> Self {
463        let val = ConstValue::Scalar(s);
464        Self::Val(val, ty)
465    }
466}
467
468/// An unevaluated (potentially generic) constant used in MIR.
469#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for UnevaluatedConst<'tcx> { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl<'tcx> ::core::clone::TrivialClone for UnevaluatedConst<'tcx> { }
#[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_fields_are_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::marker::StructuralPartialEq for UnevaluatedConst<'tcx> { }
#[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) {
                let UnevaluatedConst {
                        def: ref __binding_0,
                        args: ref __binding_1,
                        promoted: ref __binding_2 } = *self;
                ::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)]
470#[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> ::rustc_data_structures::stable_hash::StableHash for
            UnevaluatedConst<'tcx> {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                match *self {
                    UnevaluatedConst {
                        def: ref __binding_0,
                        args: ref __binding_1,
                        promoted: ref __binding_2 } => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                        { __binding_2.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash, 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>)
                -> UnevaluatedConst<'__lifted> {
                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)]
471pub struct UnevaluatedConst<'tcx> {
472    pub def: DefId,
473    pub args: GenericArgsRef<'tcx>,
474    pub promoted: Option<Promoted>,
475}
476
477impl<'tcx> UnevaluatedConst<'tcx> {
478    #[inline]
479    pub fn shrink(self, tcx: TyCtxt<'tcx>) -> ty::AliasConst<'tcx> {
480        {
    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);
481        ty::AliasConst::new(
482            tcx,
483            ty::AliasConstKind::new_from_def_id(
484                tcx,
485                self.def,
486                ty::AliasConstInherentArgsKind::Impl,
487            ),
488            self.args,
489        )
490    }
491}
492
493impl<'tcx> UnevaluatedConst<'tcx> {
494    #[inline]
495    pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
496        UnevaluatedConst { def, args, promoted: Default::default() }
497    }
498
499    #[inline]
500    pub fn from_instance(instance: ty::Instance<'tcx>) -> Self {
501        UnevaluatedConst::new(instance.def_id(), instance.args)
502    }
503}
504
505impl<'tcx> Display for Const<'tcx> {
506    fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
507        match *self {
508            Const::Ty(_, c) => pretty_print_const(c, fmt, true),
509            Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
510            // FIXME(valtrees): Correctly print mir constants.
511            Const::Unevaluated(c, _ty) => {
512                ty::tls::with(move |tcx| {
513                    let c = tcx.lift(c);
514                    // Matches `GlobalId` printing.
515                    let instance =
516                        {
    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));
517                    fmt.write_fmt(format_args!("{0}", instance))write!(fmt, "{instance}")?;
518                    if let Some(promoted) = c.promoted {
519                        fmt.write_fmt(format_args!("::{0:?}", promoted))write!(fmt, "::{promoted:?}")?;
520                    }
521                    Ok(())
522                })
523            }
524        }
525    }
526}
527
528///////////////////////////////////////////////////////////////////////////
529// Const-related utilities
530
531impl<'tcx> TyCtxt<'tcx> {
532    pub fn span_as_caller_location(self, span: Span) -> ConstValue {
533        let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
534        let caller = self.sess.source_map().lookup_char_pos(topmost.lo());
535        self.const_caller_location(
536            Symbol::intern(
537                &caller.file.name.display(RemapPathScopeComponents::MACRO).to_string_lossy(),
538            ),
539            caller.line as u32,
540            caller.col_display as u32 + 1,
541        )
542    }
543}