Skip to main content

rustc_middle/ty/
cast.rs

1// Helpers for handling cast expressions, used in both
2// typeck and codegen.
3
4use rustc_macros::{StableHash, TyDecodable, TyEncodable};
5use rustc_span::bug;
6
7use crate::mir;
8use crate::ty::{self, Ty};
9
10/// Types that are represented as ints.
11#[derive(#[automatically_derived]
impl ::core::marker::Copy for IntTy { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for IntTy { }
#[automatically_derived]
impl ::core::clone::Clone for IntTy {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<ty::UintTy>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for IntTy {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            IntTy::U(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "U",
                    &__self_0),
            IntTy::I => ::core::fmt::Formatter::write_str(f, "I"),
            IntTy::CEnum => ::core::fmt::Formatter::write_str(f, "CEnum"),
            IntTy::Bool => ::core::fmt::Formatter::write_str(f, "Bool"),
            IntTy::Char => ::core::fmt::Formatter::write_str(f, "Char"),
        }
    }
}Debug, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for IntTy { }
#[automatically_derived]
impl ::core::cmp::PartialEq for IntTy {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (IntTy::U(__self_0), IntTy::U(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for IntTy {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<ty::UintTy>;
    }
}Eq)]
12pub enum IntTy {
13    U(ty::UintTy),
14    I,
15    CEnum,
16    Bool,
17    Char,
18}
19
20impl IntTy {
21    pub fn is_signed(self) -> bool {
22        #[allow(non_exhaustive_omitted_patterns)] match self {
    Self::I => true,
    _ => false,
}matches!(self, Self::I)
23    }
24}
25
26// Valid types for the result of a non-coercion cast
27#[derive(#[automatically_derived]
impl<'tcx> ::core::marker::Copy for CastTy<'tcx> { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl<'tcx> ::core::clone::TrivialClone for CastTy<'tcx> { }
#[automatically_derived]
impl<'tcx> ::core::clone::Clone for CastTy<'tcx> {
    #[inline]
    fn clone(&self) -> Self {
        let _: ::core::clone::AssertParamIsClone<IntTy>;
        let _: ::core::clone::AssertParamIsClone<ty::TypeAndMut<'tcx>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'tcx> ::core::fmt::Debug for CastTy<'tcx> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            CastTy::Int(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Int",
                    &__self_0),
            CastTy::Float => ::core::fmt::Formatter::write_str(f, "Float"),
            CastTy::FnPtr => ::core::fmt::Formatter::write_str(f, "FnPtr"),
            CastTy::Ptr(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Ptr",
                    &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl<'tcx> ::core::marker::StructuralPartialEq for CastTy<'tcx> { }
#[automatically_derived]
impl<'tcx> ::core::cmp::PartialEq for CastTy<'tcx> {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (CastTy::Int(__self_0), CastTy::Int(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (CastTy::Ptr(__self_0), CastTy::Ptr(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl<'tcx> ::core::cmp::Eq for CastTy<'tcx> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<IntTy>;
        let _: ::core::cmp::AssertParamIsEq<ty::TypeAndMut<'tcx>>;
    }
}Eq)]
28pub enum CastTy<'tcx> {
29    /// Various types that are represented as ints and handled mostly
30    /// in the same way, merged for easier matching.
31    Int(IntTy),
32    /// Floating-point types.
33    Float,
34    /// Function pointers.
35    FnPtr,
36    /// Raw pointers.
37    Ptr(ty::TypeAndMut<'tcx>),
38}
39
40/// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html)
41/// (or rustc_hir_analysis/check/cast.rs).
42#[derive(#[automatically_derived]
impl ::core::marker::Copy for CastKind { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for CastKind { }
#[automatically_derived]
impl ::core::clone::Clone for CastKind {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for CastKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                CastKind::PtrPtrCast => "PtrPtrCast",
                CastKind::PtrAddrCast => "PtrAddrCast",
                CastKind::AddrPtrCast => "AddrPtrCast",
                CastKind::NumericCast => "NumericCast",
                CastKind::EnumCast => "EnumCast",
                CastKind::PrimIntCast => "PrimIntCast",
                CastKind::U8CharCast => "U8CharCast",
                CastKind::ArrayPtrCast => "ArrayPtrCast",
                CastKind::FnPtrPtrCast => "FnPtrPtrCast",
                CastKind::FnPtrAddrCast => "FnPtrAddrCast",
            })
    }
}Debug, const _: () =
    {
        impl<'tcx, __E: ::rustc_middle::ty::codec::TyEncoder<'tcx>>
            ::rustc_serialize::Encodable<__E> for CastKind {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        CastKind::PtrPtrCast => { 0usize }
                        CastKind::PtrAddrCast => { 1usize }
                        CastKind::AddrPtrCast => { 2usize }
                        CastKind::NumericCast => { 3usize }
                        CastKind::EnumCast => { 4usize }
                        CastKind::PrimIntCast => { 5usize }
                        CastKind::U8CharCast => { 6usize }
                        CastKind::ArrayPtrCast => { 7usize }
                        CastKind::FnPtrPtrCast => { 8usize }
                        CastKind::FnPtrAddrCast => { 9usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
            }
        }
    };TyEncodable, const _: () =
    {
        impl<'tcx, __D: ::rustc_middle::ty::codec::TyDecoder<'tcx>>
            ::rustc_serialize::Decodable<__D> for CastKind {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => { CastKind::PtrPtrCast }
                    1usize => { CastKind::PtrAddrCast }
                    2usize => { CastKind::AddrPtrCast }
                    3usize => { CastKind::NumericCast }
                    4usize => { CastKind::EnumCast }
                    5usize => { CastKind::PrimIntCast }
                    6usize => { CastKind::U8CharCast }
                    7usize => { CastKind::ArrayPtrCast }
                    8usize => { CastKind::FnPtrPtrCast }
                    9usize => { CastKind::FnPtrAddrCast }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `CastKind`, expected 0..10, actual {0}",
                                n));
                    }
                }
            }
        }
    };TyDecodable, const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for CastKind {
            #[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 {
                    CastKind::PtrPtrCast => {}
                    CastKind::PtrAddrCast => {}
                    CastKind::AddrPtrCast => {}
                    CastKind::NumericCast => {}
                    CastKind::EnumCast => {}
                    CastKind::PrimIntCast => {}
                    CastKind::U8CharCast => {}
                    CastKind::ArrayPtrCast => {}
                    CastKind::FnPtrPtrCast => {}
                    CastKind::FnPtrAddrCast => {}
                }
            }
        }
    };StableHash)]
43pub enum CastKind {
44    PtrPtrCast,
45    PtrAddrCast,
46    AddrPtrCast,
47    NumericCast,
48    EnumCast,
49    PrimIntCast,
50    U8CharCast,
51    ArrayPtrCast,
52    FnPtrPtrCast,
53    FnPtrAddrCast,
54}
55
56impl<'tcx> CastTy<'tcx> {
57    /// Returns `Some` for integral/pointer casts.
58    /// Casts like unsizing casts will return `None`.
59    pub fn from_ty(t: Ty<'tcx>) -> Option<CastTy<'tcx>> {
60        match *t.kind() {
61            ty::Bool => Some(CastTy::Int(IntTy::Bool)),
62            ty::Char => Some(CastTy::Int(IntTy::Char)),
63            ty::Int(_) => Some(CastTy::Int(IntTy::I)),
64            ty::Infer(ty::InferTy::IntVar(_)) => Some(CastTy::Int(IntTy::I)),
65            ty::Infer(ty::InferTy::FloatVar(_)) => Some(CastTy::Float),
66            ty::Uint(u) => Some(CastTy::Int(IntTy::U(u))),
67            ty::Float(_) => Some(CastTy::Float),
68            ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)),
69            ty::RawPtr(ty, mutbl) => Some(CastTy::Ptr(ty::TypeAndMut { ty, mutbl })),
70            ty::FnPtr(..) => Some(CastTy::FnPtr),
71            _ => None,
72        }
73    }
74}
75
76/// Returns `mir::CastKind` from the given parameters.
77pub fn mir_cast_kind<'tcx>(from_ty: Ty<'tcx>, cast_ty: Ty<'tcx>) -> mir::CastKind {
78    let from = CastTy::from_ty(from_ty);
79    let cast = CastTy::from_ty(cast_ty);
80    let cast_kind = match (from, cast) {
81        (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
82            mir::CastKind::PointerExposeProvenance
83        }
84        (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PointerWithExposedProvenance,
85        (Some(CastTy::Int(_)), Some(CastTy::Int(_))) => mir::CastKind::IntToInt,
86        (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => mir::CastKind::FnPtrToPtr,
87
88        (Some(CastTy::Float), Some(CastTy::Int(_))) => mir::CastKind::FloatToInt,
89        (Some(CastTy::Int(_)), Some(CastTy::Float)) => mir::CastKind::IntToFloat,
90        (Some(CastTy::Float), Some(CastTy::Float)) => mir::CastKind::FloatToFloat,
91        (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_))) => mir::CastKind::PtrToPtr,
92
93        (_, _) => {
94            ::rustc_span::macros::bug_impl(None,
    format_args!("Attempting to cast non-castable types {0:?} and {1:?}",
        from_ty, cast_ty), Location::caller())bug!("Attempting to cast non-castable types {:?} and {:?}", from_ty, cast_ty)
95        }
96    };
97    cast_kind
98}