rustc_mir_build/thir/
constant.rs

1use rustc_abi::Size;
2use rustc_ast::{self as ast, UintTy};
3use rustc_hir::LangItem;
4use rustc_middle::bug;
5use rustc_middle::mir::interpret::LitToConstInput;
6use rustc_middle::ty::{self, ScalarInt, TyCtxt, TypeVisitableExt as _};
7use tracing::trace;
8
9use crate::builder::parse_float_into_scalar;
10
11pub(crate) fn lit_to_const<'tcx>(
12    tcx: TyCtxt<'tcx>,
13    lit_input: LitToConstInput<'tcx>,
14) -> ty::Const<'tcx> {
15    let LitToConstInput { lit, ty, neg } = lit_input;
16
17    if let Err(guar) = ty.error_reported() {
18        return ty::Const::new_error(tcx, guar);
19    }
20
21    let trunc = |n, width: ty::UintTy| {
22        let width = width
23            .normalize(tcx.data_layout.pointer_size().bits().try_into().unwrap())
24            .bit_width()
25            .unwrap();
26        let width = Size::from_bits(width);
27        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_build/src/thir/constant.rs:27",
                        "rustc_mir_build::thir::constant", ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_build/src/thir/constant.rs"),
                        ::tracing_core::__macro_support::Option::Some(27u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::constant"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("trunc {0} with size {1} and shift {2}",
                                                    n, width.bits(), 128 - width.bits()) as &dyn Value))])
            });
    } else { ; }
};trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
28        let result = width.truncate(n);
29        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_build/src/thir/constant.rs:29",
                        "rustc_mir_build::thir::constant", ::tracing::Level::TRACE,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_build/src/thir/constant.rs"),
                        ::tracing_core::__macro_support::Option::Some(29u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_build::thir::constant"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("trunc result: {0}",
                                                    result) as &dyn Value))])
            });
    } else { ; }
};trace!("trunc result: {}", result);
30
31        ScalarInt::try_from_uint(result, width)
32            .unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("expected to create ScalarInt from uint {0:?}",
        result))bug!("expected to create ScalarInt from uint {:?}", result))
33    };
34
35    let valtree = match (lit, ty.kind()) {
36        (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
37            let str_bytes = s.as_str().as_bytes();
38            ty::ValTree::from_raw_bytes(tcx, str_bytes)
39        }
40        (ast::LitKind::Str(s, _), ty::Str) if tcx.features().deref_patterns() => {
41            // String literal patterns may have type `str` if `deref_patterns` is enabled, in order
42            // to allow `deref!("..."): String`.
43            let str_bytes = s.as_str().as_bytes();
44            ty::ValTree::from_raw_bytes(tcx, str_bytes)
45        }
46        (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _))
47            if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind()
48                && let ty::Uint(UintTy::U8) = ty.kind() =>
49        {
50            ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str())
51        }
52        (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(inner_ty) | ty::Array(inner_ty, _))
53            if tcx.features().deref_patterns()
54                && let ty::Uint(UintTy::U8) = inner_ty.kind() =>
55        {
56            // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is
57            // enabled, in order to allow, e.g., `deref!(b"..."): Vec<u8>`.
58            ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str())
59        }
60        (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
61            ty::ValTree::from_scalar_int(tcx, n.into())
62        }
63        (ast::LitKind::CStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if #[allow(non_exhaustive_omitted_patterns)] match inner_ty.kind() {
    ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr) => true,
    _ => false,
}matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) =>
64        {
65            // A CStr is a newtype around a byte slice, so we create the inner slice here.
66            // We need a branch for each "level" of the data structure.
67            let bytes = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str());
68            ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, bytes, *inner_ty)])
69        }
70        (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => {
71            let scalar_int = trunc(n.get(), *ui);
72            ty::ValTree::from_scalar_int(tcx, scalar_int)
73        }
74        (ast::LitKind::Int(n, _), ty::Int(i)) => {
75            let scalar_int = trunc(
76                if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() },
77                i.to_unsigned(),
78            );
79            ty::ValTree::from_scalar_int(tcx, scalar_int)
80        }
81        (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int(tcx, b.into()),
82        (ast::LitKind::Float(n, _), ty::Float(fty)) => {
83            let bits = parse_float_into_scalar(n, *fty, neg).unwrap_or_else(|| {
84                tcx.dcx().bug(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("couldn\'t parse float literal: {0:?}",
                lit_input.lit))
    })format!("couldn't parse float literal: {:?}", lit_input.lit))
85            });
86            ty::ValTree::from_scalar_int(tcx, bits)
87        }
88        (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int(tcx, c.into()),
89        (ast::LitKind::Err(guar), _) => return ty::Const::new_error(tcx, guar),
90        _ => return ty::Const::new_misc_error(tcx),
91    };
92
93    ty::Const::new_value(tcx, valtree, ty)
94}